Verwendete AudioPID Merken

Das Original Benutzerinterface Neutrino-SD incl. zapit, sectionsd, yWeb etc...
Janus
Einsteiger
Einsteiger
Beiträge: 232
Registriert: Montag 30. Juli 2001, 00:00

Beitrag von Janus »

dann dekodiert ihr den Audiostrom und analysiert die Daten mit Hilfe einer Sprachdatenbank
Schonmal auf den Stream-Descriptor geschaut?
Meist ;) wird die Sprachkennung (deu, eng, fra usf) korrekt mitgesendet.

Wie reproduzierbar diese Info abgelegt wird, ist letztlich völlig gleichgültig. Die PID erscheint mir allerdings schon recht optimal. (die grüne Taste gibt es ja auch immer noch...)

Die eigentliche Frage lautet doch: Feature ja/nein
Dann noch eine Zusatzfrage: Zuschaltbar ja/nein

Meine Meinung:
Feature = ja, gerne
Zuschaltbar = von mir aus (ich brauche es ja nicht zu coden)

Janus
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

Du hast kein bißchen verstanden worum es mir eigentlich geht, naja, egal.
Janus hat geschrieben: Zuschaltbar = von mir aus (ich brauche es ja nicht zu coden)
Genau, und ich muß es nicht einchecken. ;)

SCNR.

cu
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

Ich will's nur noch einmal verdeutlichen.

Nimm ein Netzwerk, da gibt es IP und MAC.
Die IP ist dann der Stream-Deskriptor und die MAC die AudioPID.

Du willst jetzt nur die MAC speichern und im Notfall halt die IP nehmen.

Wird dir so eher klar, daß das falschrum gedacht ist?

Die Logik müßte so sein, daß wenn die Information, die man aus dem Streamdeskriptor entnimmt nicht reicht man dann erst die AudioPID nimmt.

Wenn sich jemand hinsetzt und das codet fände ich's halt schlecht wenn man das Pferd erstmal von hinten aufzäumt und der untersten Schicht Vorrang vor der obersten gibt.

Klar, das man das erstmal prüfen müßte wie gut sich sowas bewährt und wenn's nicht klappt, dann war's halt ein schlechter Ansatz von mir. ;) Vielleicht hast du's ja auch schon gemacht und festgestellt, daß deine Idee besser ist. Allerdings hast du's mir dann nicht wirklich verständlich gemacht. :)

Aber generell die höhere Schicht erstmal zu ignorieren, das stört mich eben.
Janus
Einsteiger
Einsteiger
Beiträge: 232
Registriert: Montag 30. Juli 2001, 00:00

Beitrag von Janus »

Du hast kein bißchen verstanden worum es mir eigentlich geht
Das fürchte ich allerdings auch! 8)
Aber das sollte Dich nicht traurig stimmen, ich kann mich auch nicht immer verständlich ausdrücken... ;)

Janus
essu
Tuxboxer
Tuxboxer
Beiträge: 2452
Registriert: Montag 21. Oktober 2002, 10:04

Beitrag von essu »

Ich bin auch eher für wohl durchdachte und genial programmierte Lösungen, das Reinheitsgebot für Neutrinocode hätte man aber schon 1539 einführen müssen.

Ich kann es auch von der praktischen Seite betrachten:
Ein Feature wird nachgefragt, jemand bietet eine Lösung an (nicht ohne darauf hinzuweisen, dass es ein quick `n edirty patch ist), die Lösung ist zumindest befriedigend, hat auch keine für den User/die Userin erkennbaren Nachteile. Jetzt verbessert er die Lösung und muss hören, dass sie nicht optimal ist. An seiner Stelle würde ich sagen: So what? Niemand muss meinen Patch benutzen und wenn jemand weiss, wie es besser geht, dann soll ers halt besser machen.

Ob das sehr motivierend ist, sei mal dahin gestellt.

Doch eins zum Trost von einem (nicht ganz) unbekannten Zitatgeber:
mhh, Neutrino ist schon etwas seltsam - nicht umsonst braucht man da viel Weihwasser (nicht nur wegen den vielen daemons)
Schon gelesen ???
ENIGMA-DOC
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

Hmm, OK, so eine Diskussion wird schonmal hitzig.

Es ging mir eigentlich darum, warum ich nicht dafür war, es in dieser Form einzuchecken.

Ich hab damals aber schon gesagt, daß das nur meine persönliche Entscheidung war und ein anderer Developer da gerne anderer Meinung sein darf.

Aber Barf hat das ja auch nie im CVS drin haben wollen, er hat es ja selber eher als persönlichen Patch verstanden, was ja auch OK ist.

Die Yadis bauen es ja auch ein, liegt ja in deren Ermessen. Man sollte halt nur die Nachteile kennen.

Wenn ich hier was sage, dann ist es eigentlich immer nur meine persönliche Meinung auch wenn es sich schon mal anders anhören mag. Wie gesagt, die hitzigen Diskussionen.. ;)
insolvenzia
Erleuchteter
Erleuchteter
Beiträge: 455
Registriert: Montag 5. August 2002, 19:42

Beitrag von insolvenzia »

Npq hat geschrieben: Aber Barf hat das ja auch nie im CVS drin haben wollen
Natürlich nicht, dehalb behält er ja alles für sich. Habe ich hier auch so verstanden:
http://forum.tuxbox-cvs.sourceforge.net ... +zum+image
Dort schreibt er nur aus Langeweile:"Ich wurde mich freuen, falls die Developers das Ding im CDK integrieren wurde."
Rechtschreibfehler seien ihm verziehen. Man sieht das aber auch schon daran, das er DIFFs posted, dann will er es ja garnicht im CVS haben, sondern hat viel mehr Spaß daran, das nach jeder größeren Änderung im CVS er selbst die User hier zufrieden stellen muß.
Bei dem Zapit Patch ist es das gleiche, aber das kannst Du Dir mit der Suchfunktion selbst rausfischen.

Sorry, aber ihr seit schon ein komisches Fölkchen.. 1mal / Jahr reinschauen hier, kopfschütteln, und nächstes Jahr wiederkommen um festzustellen das keinerlei Innovation stattgefunden hat, weil ihr alle neuen innovativen Developer vergrault habt. Ich stelle das jedes Jahr so fest.
Oder ist das nur so meine Meinung?
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

OK, meine Entschuldigung an Barf, er sagte damals:

"Weil ich nicht Schreibrecht in CVS habe (und dies ist auch nicht mein Ziel) habe ich die Verbesserung in diesem Forum veröffentlicht."

Hab das mit dem nicht-gewollten Schreibrecht auf die Patches ausgedehnt.

*duck*
essu
Tuxboxer
Tuxboxer
Beiträge: 2452
Registriert: Montag 21. Oktober 2002, 10:04

Beitrag von essu »

Npq hat geschrieben:... Man sollte halt nur die Nachteile kennen....
..und das ist auch [r|w]ichtig.
Schon gelesen ???
ENIGMA-DOC
Barf
Developer
Beiträge: 1475
Registriert: Dienstag 4. Februar 2003, 22:02

Beitrag von Barf »

Also, auch wenn es ein Paar Monaten alt ist, muss ich endlich etwas Senf rauslassen:

Es scheint so, dass Einige das auswählen von AudioPIDs zu Graalsuche macht: Irgendwie glaubt mann in das Problem P: wie Daten von in der Vorgangenheit gewählte AudioPIDs optimal ausgenützt sein soll, um jetzt dem Benutzer ein AudioPID auszuwählen.

Wie diese und andere Threads gezeigt hat, gibt es haufenweise von unterschiedliche Meinungen, um so ein Wahl automatisch zu treffen. (Und: Unterschiedliche Meinungen weil es sich um Benutzerpräferenzen handelt, nicht um schlecht verstandene Technik!) Falls ich Npq richtig verstanden habe, soll eine akzeptable Lösung darauf basieren, dass "die Sprache" irgendwie "high-level" identifiziert werden, abgespeichert, und danach, falls möglich, wieder hergestellt werden. Alles anders ist "nicht DVB-konform". Auch falls so eine Lösung sich implementieren liess, wäre sicherlich nicht alle Leute damit einverstanden -- z.B. falls mann immer Originalton will (unabhängig von Sprache). Eine für allen akzeptable Lösung müssen sicherlich ein Skriptsprache enthalten -- sollen wir Guile, TCL, Perl oder Python in Neutrino/Enigma embedden?

Ich sage NICHT, dass weil Problem P zu schweirig ist, soll mann sich mit einem einfachen, unvollständig, Lösung begnügen. Ich sage, dass ein wohldefinierte Problem P gibt es nicht!! Lösung L ist nicht eine Lösung auf Problem P, sondern ein Funktionalität, was in den "meisten" Fällen macht was die "meisten" Leuten wollen, ausserdem (wichtig!) bietet dem Benutzer keine Überraschungen.

Für Graalsjäger, die sowohl Problem P als auch seine optimale Lösung L suchen, habe ich nicht viel respekt. Tragisch wird es, wenn die Entwicklung verhindert wird.

Noch 'ne Frage: Wie kann es DVB-konform sein, AudioPIDs zwischen Umschaltungen zu behalten (wie jetzt), aber falls dieses Gedächnis ein Runterfahren/Hochfahren überlebt, sind wir plötzlig DVB-inkonform???

Janus wrote:
Frage am Rande: Warum nimmst Du auch die Dienste mit in die Auflistung, die garkeine weiteren Audio-Pids haben? Da Neutrino in solchen Fällen keine Audiostream-Auswahl anbietet, müssten doch diese Infos verfügbar und nutzbar sein...
Auf jeden Fall würde so die Datei um Einiges kleiner.
(und schneller gelesen und gespeichert)
Gegen dein Vorschlag spricht, dass du es vorgeschlagen hast und nicht ich :P . In der Tat, ich habe es seit Monaten implementiert, nur zu Veröffentlichung bin ich noch nicht gekommen. Mal sehen...
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

Python, um eine Tabelle zu parsen?

Also Premiere 4:
Aus PMT ersichtlich ist, daß es 3 Audio-Streams gibt, einer hat Component_tag 3, der andere 6, der dritte 7.

Blick in die present/following der EIT sagt, daß die Component-Description "englisch" ist für 6, "deutsch" für 3 und "Dolby Digital 5.1" für 7

Da bekommt übrigens auch Neutrino die Info her.

So, und das Problem ist, und da gebe ich dir recht, daß die ISO639-language descriptors sowohl in der PMT als auch in der EIT als "DEU", also deutsch betitelt sind.

Man müßte halt ausprobieren welche Kriterien man da evtl. noch dazu nimmt wenn das "englisch" fehlt (Reihenfolge in der PMT z.B.).

DVB-konform oder nicht, es ist halt fehleranfällig wenn man die Audio-PID direkt speichert. Die Einträge in der PMT sind zumindest die richtigen Audio-Ströme für den entsprechenden Service.
Sepp776
Semiprofi
Semiprofi
Beiträge: 1173
Registriert: Samstag 1. September 2001, 00:00

Beitrag von Sepp776 »

Barf hat geschrieben:Ich sage NICHT, dass weil Problem P zu schweirig ist, soll mann sich mit einem einfachen, unvollständig, Lösung begnügen. Ich sage, dass ein wohldefinierte Problem P gibt es nicht!!
Naja, nur weil viele Leute unterschiedliche Präferenzen haben heißt das ja nicht dass es keine Lösung gibt. Wenn es möglich ist die vorhandenen Tonspuren automatisch zu indentifizieren, kann man doch jedes vom Nutzer gewünschte Verhalten einbauen. Zwischen den Verhaltensweisen kann man dann umschalten. Das Problem ist also, den Inhalt vorhandener Tonspuren zuverlässig zu identifizieren.

Wie ist das denn bei anderen DVB-Receivern? Gibt es diese Funktionalität irgendwo? Zuverlässig?

Schö,
Sepp.
Philips Sat
Astra 19.2°
HEAD
Einsteiger
Einsteiger
Beiträge: 313
Registriert: Freitag 14. Februar 2003, 15:59

Beitrag von HEAD »

Sepp776 hat geschrieben:
Barf hat geschrieben:Wie ist das denn bei anderen DVB-Receivern? Gibt es diese Funktionalität irgendwo? Zuverlässig?
Die sagen auch Deu/Deu steht doch in PMT . (soviel zu "DVB-konform".)
Man müßte halt ausprobieren welche Kriterien man da evtl. noch dazu nimmt wenn das "englisch" fehlt (Reihenfolge in der PMT z.B.).
if(audio1=="deu" && audio2=="deu")
audio2="eng";

solange die nicht dvb-konform senden.
essu
Tuxboxer
Tuxboxer
Beiträge: 2452
Registriert: Montag 21. Oktober 2002, 10:04

Beitrag von essu »

Npq hat geschrieben:[...]
Blick in die present/following der EIT sagt, daß die Component-Description "englisch" ist für 6, "deutsch" für 3 und "Dolby Digital 5.1" für 7

Da bekommt übrigens auch Neutrino die Info her.

So, und das Problem ist, und da gebe ich dir recht, daß die ISO639-language descriptors sowohl in der PMT als auch in der EIT als "DEU", also deutsch betitelt sind.

Man müßte halt ausprobieren welche Kriterien man da evtl. noch dazu nimmt wenn das "englisch" fehlt (Reihenfolge in der PMT z.B.).

DVB-konform oder nicht, es ist halt fehleranfällig wenn man die Audio-PID direkt speichert. Die Einträge in der PMT sind zumindest die richtigen Audio-Ströme für den entsprechenden Service.
Eigentlich ging es hier um *AudioPID merken*, was etwas anderes ist als *festgelegte Sprache wählen*, was sicherlich auch ein interessantes Feature wäre.

Fehler können dabei, wenn ich das richtig sehe nur auftreten, wenn die gespeicherte AudioPID nicht mehr vorhanden ist. Dafür Vorsorge zu treffen sollte nicht allzu schwer sein. Wenn das ganze Feauture dann noch ein- bzw. ausschaltbar wäre, sollten eigentlich alle zufrieden sein.

BTW: *AudioPID merken* gibt es auch unter Enigma, falls es dort dvbnormkonform gelöst sein sollte, was ich nicht weiss, einfach mal spicken...
Schon gelesen ???
ENIGMA-DOC
Npq
Senior Member
Beiträge: 1339
Registriert: Donnerstag 24. April 2003, 12:12

Beitrag von Npq »

Ok, was für ein Gedanke steckt denn hinter dem "Audio-PID speichern" ?

Uli hat das bei der dbox1 gemacht, weil er der Meinung war, das wäre schneller als erst die Tabellen zu parsen. Dabei ging es um Geschwindigkeit. Allerdings hat er das bei allen PIDs durchgeführt.
essu
Tuxboxer
Tuxboxer
Beiträge: 2452
Registriert: Montag 21. Oktober 2002, 10:04

Beitrag von essu »

Npq hat geschrieben:Ok, was für ein Gedanke steckt denn hinter dem "Audio-PID speichern" ?[...]
Es ist der Versuch, komfortabel zu sein und nicht nach jedem Neustart eine früher gewählte AudioPID erneut einstellen zu müssen, im Gegensatz zu *festgelegte Sprache wählen* wo der Audiokanal gewählt wird, der der gewünschten Sprache entspricht.
BTW: Das Problem, dass die AudioPID nicht mehr existiert ist, soweit ich sehen kann, schon berücksichtigt.

Was dieses Feature nicht leistet:
- z.B. Sprachen, die nicht (mehr) existieren zu erzeugen ;)
- 100%ige Sicherheit vor PID-Tausch der Sender geben
(Im Prinzip ist es ähnlich wie zapit.conf, auch dort gibt es keine Gewissheit, dass lastChannelTV oder lastSatellitePosition später noch in dieser Form existieren, trotzdem werden sie gespeichert)
Schon gelesen ???
ENIGMA-DOC
Barf
Developer
Beiträge: 1475
Registriert: Dienstag 4. Februar 2003, 22:02

Beitrag von Barf »

Falls es jemanden intressiert:

Ich habe aktualisierte Versionen für sowohl das Patch als auch das kompilierte zapit auf meine dBox-Page (WWW-Taste unten) abgelegt. Die neue Version implementiert ein Vorschlag von einem Forumsmitglied (kann leider nicht finden wer): nur die Kanälen mit tatsächlich > 1 Audiokanal abspeichern.

Keep barfing!
lollyxy
Interessierter
Interessierter
Beiträge: 51
Registriert: Donnerstag 17. Juni 2004, 12:26

Beitrag von lollyxy »

Kann es sein dass das diff im neuen CVS schon nicht mehr funktioniert? Bei mir läufts nicht durch, gibts da schon ne Lösung?
Barf
Developer
Beiträge: 1475
Registriert: Dienstag 4. Februar 2003, 22:02

Beitrag von Barf »

Der Patch namens zapit.cpp-patch-2005-02-20 appliziert zum aktuellen CVS-Version:

Code: Alles auswählen

patching file zapit.cpp
Hunk #4 succeeded at 181 (offset 1 line).
Hunk #5 succeeded at 240 (offset 1 line).
Hunk #6 succeeded at 400 (offset 1 line).
Hunk #7 succeeded at 420 (offset 1 line).
Hunk #8 succeeded at 481 (offset 1 line).
("offset 1 line" ist harmlos.)
lollyxy
Interessierter
Interessierter
Beiträge: 51
Registriert: Donnerstag 17. Juni 2004, 12:26

Beitrag von lollyxy »

zapit.cpp-1.367 2005-02-20 11:00:38.000000000 +0100

Also das diff bezieht sich ja auf die zapit 1.367. Jetzt sind wir bei 1.37
Liegts vielleicht daran. Habe alles an der richtigen Stelle eingetragen u. bekomme ein undeclare ( audio map it) in zeile 188 u. 189 also hier
audio_map_it != audio_map.end();
audio_map_it++) {

Habe ich da was übersehen??
Barf
Developer
Beiträge: 1475
Registriert: Dienstag 4. Februar 2003, 22:02

Beitrag von Barf »

Also das diff bezieht sich ja auf die zapit 1.367. Jetzt sind wir bei 1.37
(meinst 1.370.) offensichtlich nicht, weil der Patch appliziert.

Bitte deine Fehlermeldungen posten (angefangen mit dem Patchen vom jungfraulichen Sourcen), nicht deine Vermutungen.
lollyxy
Interessierter
Interessierter
Beiträge: 51
Registriert: Donnerstag 17. Juni 2004, 12:26

Beitrag von lollyxy »

/*
* $Id: zapit.cpp,v 1.370 2005/03/14 19:58:48 mws Exp $
*
* zapit - d-box2 linux project
*
* (C) 2001, 2002 by Philipp Leusmann <faralla@berlios.de>
* (C) 2002, 2003 by Andreas Oberritter <obi@tuxbox-cvs.sourceforge.net>
*
* 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.
*
*/

/*
Options:
-d Debugmode: Don't fork, additionally generate debugging messages

-q Be quiet.

Signal handling:
SIGTERM, SIGHUP: Terminates zapit (gracefully)
SIGUSR1: Toggles debug mode
*/


/* system headers */
#include <csignal>
#include <fcntl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// AudioPIDs per channel are saved here between sessions.
// define to /dev/null to disable
#define AUDIO_CONFIG_FILE "/var/tuxbox/config/zapit/audioPIDs.data"

/* tuxbox headers */
#include <configfile.h>
#include <connection/basicserver.h>

/* zapit headers */
#include <zapit/audio.h>
#include <zapit/aviaext.h>
#include <zapit/cam.h>
#include <zapit/client/msgtypes.h>
#include <zapit/dmx.h>
#include <zapit/debug.h>
#include <zapit/frontend.h>
#include <zapit/getservices.h>
#include <zapit/pat.h>
#include <zapit/pmt.h>
#include <zapit/scan.h>
#include <zapit/settings.h>
#include <zapit/video.h>
#include <zapit/xmlinterface.h>
#include <zapit/zapit.h>


/* the conditional access module */
CCam *cam = NULL;
/* the configuration file */
CConfigFile config(',', false);
/* the event server */
CEventServer *eventServer = NULL;
/* the dvb audio device */
CAudio *audioDecoder = NULL;
/* the aviaEXT device */
CAViAext *aviaExtDriver = NULL;
/* the dvb frontend device */
CFrontend *frontend = NULL;
/* the dvb video device */
CVideo *videoDecoder = NULL;
/* the current channel */
CZapitChannel *channel = NULL;
/* the transponder scan xml input */
xmlDocPtr scanInputParser = NULL;
/* the bouquet manager */
CBouquetManager *bouquetManager = NULL;
/* the mpeg2 ts->pes demux devices */
CDemux *audioDemux = NULL;
CDemux *pcrDemux = NULL;
CDemux *teletextDemux = NULL;
CDemux *videoDemux = NULL;
map<t_channel_id, unsigned short> audio_map;



/* current zapit mode */
enum {
TV_MODE = 0x01,
RADIO_MODE = 0x02,
RECORD_MODE = 0x04
};

int currentMode;
bool playbackStopForced = false;
int debug = 0;

int waitForMotor = 0;
int motorRotationSpeed = 0; //in 0.1 degrees per second
diseqc_t diseqcType;

/* near video on demand */
tallchans nvodchannels; // tallchans defined in "bouquets.h"
bool current_is_nvod = false;

/* list of all channels (services) */
tallchans allchans; // tallchans defined in "bouquets.h"

/* transponder scan */
transponder_list_t transponders;

pthread_t scan_thread;
extern int found_transponders;
extern int processed_transponders;
extern int found_channels;
extern short curr_sat;
extern short scan_runs;
extern void get_transponder (TP_params *TP);
extern int scan_transponder(TP_params *TP);
extern void scan_clean(void);
extern short abort_scan;


CZapitClient::bouquetMode bouquetMode = CZapitClient::BM_CREATEBOUQUETS;
CZapitClient::scanType scanType = CZapitClient::ST_ALL;

/* the map which stores the wanted cable/satellites */
std::map<uint8_t, std::string> scanProviders;
/* the map which stores the diseqc 1.2 motor positions */
extern std::map<t_satellite_position, uint8_t> motorPositions;
extern std::map<t_satellite_position, uint8_t>::iterator mpos_it;

extern std::map<string, t_satellite_position> satellitePositions;

bool standby = true;

uint32_t lastChannelRadio;
uint32_t lastChannelTV;

void saveSettings(bool write)
{
if (channel) {
// now save the lowest channel number with the current channel_id
int c = ((currentMode & RADIO_MODE) ? bouquetManager->radioChannelsBegin() : bouquetManager->tvChannelsBegin()).getLowestChannelNumberWithChannelID(channel->getChannelID());

if (c >= 0)
if ((currentMode & RADIO_MODE))
lastChannelRadio = c;
else
lastChannelTV = c;
}

if (write) {
if (config.getBool("saveLastChannel", true))
{
config.setInt32("lastChannelMode", (currentMode & RADIO_MODE) ? 1 : 0);

config.setInt32("lastChannelRadio", lastChannelRadio);
config.setInt32("lastChannelTV", lastChannelTV);
}

config.setInt32("lastSatellitePosition", frontend->getCurrentSatellitePosition());
config.setInt32("diseqcRepeats", frontend->getDiseqcRepeats());
config.setInt32("diseqcType", frontend->getDiseqcType());

if (config.getModifiedFlag())
config.saveConfig(CONFIGFILE);

FILE *audio_config_file = fopen(AUDIO_CONFIG_FILE, "w");
if (audio_config_file)
{
for (map<t_channel_id, unsig
ned short>::iterator audio_map_it = audio_map.begin();
audio_map_it != audio_map.end();
audio_map_it++)
{
fwrite(&(audio_map_it->first), sizeof(t_channel_id), 1,
audio_config_file);
fwrite(&(audio_map_it->second), sizeof(unsigned short), 1,
audio_config_file);
}
fclose(audio_config_file);
}
}
}

CZapitClient::responseGetLastChannel load_settings(void)
{
FILE *audio_config_file = fopen(AUDIO_CONFIG_FILE, "r");
if (audio_config_file) {
t_channel_id chan;
unsigned short apid;
while (! feof(audio_config_file)) {
fread(&chan, sizeof(t_channel_id), 1, audio_config_file);
fread(&apid, sizeof(unsigned short), 1, audio_config_file);
//printf("**** Old channelinfo: %d %d\n", (int) chan, (int) apid);
audio_map[chan] = apid;
}
fclose(audio_config_file);
}

CZapitClient::responseGetLastChannel lastchannel;

if (currentMode & RADIO_MODE)
lastchannel.mode = 'r';
else
lastchannel.mode = 't';

lastchannel.channelNumber = (currentMode & RADIO_MODE) ? lastChannelRadio : lastChannelTV;
return lastchannel;
}


/*
* - find transponder
* - stop teletext, video, audio, pcr
* - tune
* - set up pids
* - start pcr, audio, video, teletext
* - start descrambler
*
* return 0 on success
* return -1 otherwise
*
*/

static transponder_id_t tuned_transponder_id = TRANSPONDER_ID_NOT_TUNED;
static int pmt_update_fd = -1;
static bool update_pmt = false;
void
remember_selected_audio()
{
if (channel) {
audio_map[channel->getServiceId()] = channel->getAudioPid();
DBG("*** Remembering apid = %d for channel (service-id) = %d", channel->getAudioPid(), channel->getServiceId());
}
}


int zapit(const t_channel_id channel_id, bool in_nvod, transponder_id_t transponder_id)
{
bool transponder_change;
tallchans_iterator cit;
transponder_id_t current_transponder_id;
remember_selected_audio();

DBG("tuned_transponder_id: " PRINTF_TRANSPONDER_ID_TYPE, tuned_transponder_id);

if (transponder_id == TRANSPONDER_ID_NOT_TUNED) /* usual zap */
{
if (in_nvod) {
current_is_nvod = true;
cit = nvodchannels.find(channel_id);

if (cit == nvodchannels.end()) {
DBG("channel_id " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " not found", channel_id);
return -1;
}
}
else {
current_is_nvod = false;
cit = allchans.find(channel_id);

if (currentMode & RADIO_MODE) {
if ((cit == allchans.end()) || (cit->second.getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE)) {
DBG("channel_id " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " not found", channel_id);
return -1;
}
}
else {
if (cit == allchans.end() || (cit->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE)) {
DBG("channel_id " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " not found", channel_id);
return -1;
}
}
}

/* store the new channel */
if ((!channel) || (channel_id != channel->getChannelID()))
channel = &(cit->second);

current_transponder_id = channel->getTransponderId();
}
else /* nvod subservice zap */
{
current_transponder_id = transponder_id;
}

stopPlayBack();

/* have motor move satellite dish to satellite's position if necessary */
if ((diseqcType == DISEQC_1_2) && (motorPositions[channel->getSatellitePosition()] != 0))
{
if ((frontend->getCurrentSatellitePosition() != channel->getSatellitePosition()))
{
printf("[zapit] currentSatellitePosition = %d, satellitePosition = %d\n", frontend->getCurrentSatellitePosition(), channel->getSatellitePosition());
printf("[zapit] motorPosition = %d\n", motorPositions[channel->getSatellitePosition()]);
frontend->positionMotor(motorPositions[channel->getSatellitePosition()]);

waitForMotor = abs(channel->getSatellitePosition() - frontend->getCurrentSatellitePosition()) / motorRotationSpeed; //assuming 1.8 degrees/second motor rotation speed for the time being...
printf("[zapit] waiting %d seconds for motor to turn satellite dish.\n", waitForMotor);
eventServer->sendEvent(CZapitClient::EVT_ZAP_MOTOR, CEventServer::INITID_ZAPIT, &waitForMotor, sizeof(waitForMotor));
sleep(waitForMotor);

frontend->setCurrentSatellitePosition(channel->getSatellitePosition());
}
}

/* if channel's transponder does not match the transponder tuned before ... */
if (current_transponder_id != tuned_transponder_id) {

/* ... tune to it if not in record mode ... */
if (currentMode & RECORD_MODE)
return -1;

transponder_list_t::iterator t;
t = transponders.find(current_transponder_id);
if (t == transponders.end())
return -1;

int diff = frontend->setParameters(
&t->second.feparams, t->second.polarization, t->second.DiSEqC);
switch (diff) {
case -1:
WARN("tuning failed\n");
tuned_transponder_id = TRANSPONDER_ID_NOT_TUNED;
return -1;
case 0:
break;
default:
WARN("tuned frequency does not match requested frequency. difference: %u\n", diff);
break;
}

transponder_change = true;

tuned_transponder_id = current_transponder_id;
}
else {
transponder_change = false;
}

CZapitChannel *thisChannel;

if (transponder_id == TRANSPONDER_ID_NOT_TUNED)
{
thisChannel = channel;
if (thisChannel->getServiceType() == ST_NVOD_REFERENCE_SERVICE) {
current_is_nvod = true;
saveSettings(false);
return 0;
}
}
else
{
thisChannel = new CZapitChannel(channel->getName(),
channel_id & 0xffff,
GET_TRANSPORT_STREAM_ID_FROM_TRANSPONDER_ID(transponder_id),
GET_ORIGINAL_NETWORK_ID_FROM_TRANSPONDER_ID(transponder_id),
1,
frontend->getDiseqcPosition(),
channel->getSatellitePosition());
}

/* search pids if they are unknown */
#ifdef USE_PID_CACHE
if (thisChannel->getPidsFlag() == false)
#endif
{
bool failed = false;
unsigned char audioChannel = thisChannel->getAudioChannelIndex();

thisChannel->resetPids();

DBG("looking up pids for channel_id " PRINTF_CHANNEL_ID_TYPE, thisChannel->getChannelID());

/* get program map table pid from program association table */
if (thisChannel->getPmtPid() == NONE)
if (parse_pat(thisChannel) < 0) {
WARN("pat parsing failed");
failed = true;
}

/* parse program map table and store pids */
if ((!failed) && (parse_pmt(thisChannel) < 0)) {
WARN("pmt parsing failed");
failed = true;
}

thisChannel->setAudioChannel(audioChannel);
thisChannel->setAudioChannel(audioChannel);

if ((!failed) && (thisChannel->getAudioPid() == NONE) && (thisChannel->getVideoPid() == NONE)) {
WARN("neither audio nor video pid found");
failed = true;
}

if (failed) {
thisChannel->resetPids();
if (channel != thisChannel)
delete thisChannel;
return -1;
}
}

if (transponder_change == true)
thisChannel->getCaPmt()->ca_pmt_list_management = 0x03;
else
thisChannel->getCaPmt()->ca_pmt_list_management = 0x04;
DBG("***Now trying to get audio right: %d\t%d\t%d\t%d",
thisChannel->getAudioChannelCount(),
thisChannel->getAudioChannel(0)->pid,
thisChannel->getServiceId(),
audio_map[thisChannel->getServiceId()]);
for (int i = 0; i < thisChannel->getAudioChannelCount(); i++) {
if (thisChannel->getAudioChannel(i)->pid == audio_map[thisChannel->getServiceId()]) {
DBG("***** Setting audio!\n");
thisChannel->setAudioChannel(i);
}
}

startPlayBack(thisChannel);
cam->setCaPmt(thisChannel->getCaPmt());
saveSettings(false);

if (update_pmt)
pmt_set_update_filter(thisChannel, &pmt_update_fd);

if (channel != thisChannel)
delete thisChannel;

return 0;
}

int select_nvod_subservice_num(int num)
{
t_original_network_id original_network_id;
t_transport_stream_id transport_stream_id;
t_service_id service_id;

if ((!channel) || (channel->getServiceType() != ST_NVOD_REFERENCE_SERVICE) || (num < 0))
return -1;

if (tuned_transponder_id != channel->getTransponderId())
zapit(channel->getChannelID(), false, TRANSPONDER_ID_NOT_TUNED);

if (nvod_service_ids(channel->getTransportStreamId(), channel->getOriginalNetworkId(), channel->getServiceId(),
num, &transport_stream_id, &original_network_id, &service_id) < 0)
return -1;

DBG("tsid: %04x, onid: %04x, sid: %04x\n", transport_stream_id, original_network_id, service_id);

return zapit(CREATE_CHANNEL_ID, false, CREATE_TRANSPONDER_ID_FROM_SATELLITEPOSITION_ORIGINALNETWORK_TRANSPORTSTREAM_ID(channel->getSatellitePosition(), original_network_id, transport_stream_id));
}

int change_audio_pid(uint8_t index)
{
if ((!audioDemux) || (!audioDecoder) || (!channel))
return -1;

/* stop demux filter */
if (audioDemux->stop() < 0)
return -1;

/* stop audio playback */
if (audioDecoder->stop() < 0)
return -1;

/* update current channel */
channel->setAudioChannel(index);
remember_selected_audio();

/* set bypass mode */
CZapitAudioChannel *currentAudioChannel = channel->getAudioChannel();

if (!currentAudioChannel) {
WARN("No current audio channel");
return -1;
}

if (currentAudioChannel->isAc3)
audioDecoder->enableBypass();
else
audioDecoder->disableBypass();

/* set demux filter */
if (audioDemux->pesFilter(channel->getAudioPid(), DMX_OUT_DECODER, DMX_PES_AUDIO) < 0)
return -1;

/* start audio playback */
if (audioDecoder->start() < 0)
return -1;

/* start demux filter */
if (audioDemux->start() < 0)
return -1;

return 0;
}

void setRadioMode(void)
{
currentMode |= RADIO_MODE;
currentMode &= ~TV_MODE;
}

void setTVMode(void)
{
currentMode |= TV_MODE;
currentMode &= ~RADIO_MODE;
}

int getMode(void)
{
if (currentMode & TV_MODE)
return CZapitClient::MODE_TV;
if (currentMode & RADIO_MODE)
return CZapitClient::MODE_RADIO;
return 0;
}

void setRecordMode(void)
{
currentMode |= RECORD_MODE;
eventServer->sendEvent(CZapitClient::EVT_RECORDMODE_ACTIVATED, CEventServer::INITID_ZAPIT );
}

void unsetRecordMode(void)
{
currentMode &= ~RECORD_MODE;
eventServer->sendEvent(CZapitClient::EVT_RECORDMODE_DEACTIVATED, CEventServer::INITID_ZAPIT );
}

int prepare_channels(fe_type_t frontendType, diseqc_t diseqcType)
{
// for the case this function is NOT called for the first time (by main())
// we clear all cannel lists, they are refilled
// by LoadServices() and LoadBouquets()
transponders.clear();
bouquetManager->clearAll();
allchans.clear(); // <- this invalidates all bouquets, too!
if (LoadServices(frontendType, diseqcType) < 0)
return -1;

INFO("LoadServices: success");
bouquetManager->loadBouquets();

return 0;
}


void parseScanInputXml(void)
{
switch (frontend->getInfo()->type) {
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", frontend->getInfo()->type);
return;
}
}

/*
* return 0 on success
* return -1 otherwise
*/
int start_scan(bool scan_mode)
{
if (!scanInputParser) {
parseScanInputXml();
if (!scanInputParser) {
WARN("scan not configured");
return -1;
}
}

bouquetManager->clearAll();
stopPlayBack();
pmt_stop_update_filter(&pmt_update_fd);
pmt_update_fd = -1;
tuned_transponder_id = TRANSPONDER_ID_NOT_TUNED;
found_transponders = 0;
found_channels = 0;
scan_runs = 1;

if (pthread_create(&scan_thread, 0, start_scanthread, (void*)scan_mode)) {
ERROR("pthread_create");
scan_runs = 0;
return -1;
}

return 0;
}


bool parse_command(CBasicMessage::Header &rmsg, int connfd)
{
DBG("cmd %d (version %d) received", rmsg.cmd, rmsg.version);

if ((standby) &&
((rmsg.cmd != CZapitMessages::CMD_SET_STANDBY) &&
(rmsg.cmd != CZapitMessages::CMD_SHUTDOWN) &&
(rmsg.cmd != CZapitMessages::CMD_SET_AE_IEC_ON) &&
(rmsg.cmd != CZapitMessages::CMD_SET_AE_IEC_OFF) &&
(rmsg.cmd != CZapitMessages::CMD_GET_AE_IEC_STATE) &&
(rmsg.cmd != CZapitMessages::CMD_GET_AE_PLAYBACK_STATE))) {
WARN("cmd %d refused in standby mode", rmsg.cmd);
return true;
}

switch (rmsg.cmd) {
case CZapitMessages::CMD_SHUTDOWN:
return false;

case CZapitMessages::CMD_ZAPTO:
{
CZapitMessages::commandZapto msgZapto;
CBasicServer::receive_data(connfd, &msgZapto, sizeof(msgZapto)); // bouquet & channel number are already starting at 0!
zapTo(msgZapto.bouquet, msgZapto.channel);
break;
}

case CZapitMessages::CMD_ZAPTO_CHANNELNR:
{
CZapitMessages::commandZaptoChannelNr msgZaptoChannelNr;
CBasicServer::receive_data(connfd, &msgZaptoChannelNr, sizeof(msgZaptoChannelNr)); // bouquet & channel number are already starting at 0!
zapTo(msgZaptoChannelNr.channel);
break;
}

case CZapitMessages::CMD_ZAPTO_SERVICEID:
case CZapitMessages::CMD_ZAPTO_SUBSERVICEID:
{
CZapitMessages::commandZaptoServiceID msgZaptoServiceID;
CZapitMessages::responseZapComplete msgResponseZapComplete;
CBasicServer::receive_data(connfd, &msgZaptoServiceID, sizeof(msgZaptoServiceID));
msgResponseZapComplete.zapStatus = zapTo_ChannelID(msgZaptoServiceID.channel_id, (rmsg.cmd == CZapitMessages::CMD_ZAPTO_SUBSERVICEID));
CBasicServer::send_data(connfd, &msgResponseZapComplete, sizeof(msgResponseZapComplete));
break;
}

case CZapitMessages::CMD_ZAPTO_SERVICEID_NOWAIT:
case CZapitMessages::CMD_ZAPTO_SUBSERVICEID_NOWAIT:
{
CZapitMessages::commandZaptoServiceID msgZaptoServiceID;
CBasicServer::receive_data(connfd, &msgZaptoServiceID, sizeof(msgZaptoServiceID));
zapTo_ChannelID(msgZaptoServiceID.channel_id, (rmsg.cmd == CZapitMessages::CMD_ZAPTO_SUBSERVICEID_NOWAIT));
break;
}

case CZapitMessages::CMD_GET_LAST_CHANNEL:
{
CZapitClient::responseGetLastChannel responseGetLastChannel;
responseGetLastChannel = load_settings();
CBasicServer::send_data(connfd, &responseGetLastChannel, sizeof(responseGetLastChannel)); // bouquet & channel number are already starting at 0!
break;
}

case CZapitMessages::CMD_GET_CURRENT_SATELLITE_POSITION:
{
int32_t currentSatellitePosition = frontend->getCurrentSatellitePosition();
CBasicServer::send_data(connfd, &currentSatellitePosition, sizeof(currentSatellitePosition));
break;
}

case CZapitMessages::CMD_SET_AUDIOCHAN:
{
CZapitMessages::commandSetAudioChannel msgSetAudioChannel;
CBasicServer::receive_data(connfd, &msgSetAudioChannel, sizeof(msgSetAudioChannel));
change_audio_pid(msgSetAudioChannel.channel);
break;
}

case CZapitMessages::CMD_SET_MODE:
{
CZapitMessages::commandSetMode msgSetMode;
CBasicServer::receive_data(connfd, &msgSetMode, sizeof(msgSetMode));
if (msgSetMode.mode == CZapitClient::MODE_TV)
setTVMode();
else if (msgSetMode.mode == CZapitClient::MODE_RADIO)
setRadioMode();
break;
}

case CZapitMessages::CMD_GET_MODE:
{
CZapitMessages::responseGetMode msgGetMode;
msgGetMode.mode = (CZapitClient::channelsMode) getMode();
CBasicServer::send_data(connfd, &msgGetMode, sizeof(msgGetMode));
break;
}

case CZapitMessages::CMD_GET_CURRENT_SERVICEID:
{
CZapitMessages::responseGetCurrentServiceID msgCurrentSID;
msgCurrentSID.channel_id = (tuned_transponder_id != TRANSPONDER_ID_NOT_TUNED) ? channel->getChannelID() : 0;
CBasicServer::send_data(connfd, &msgCurrentSID, sizeof(msgCurrentSID));
break;
}

case CZapitMessages::CMD_GET_CURRENT_SERVICEINFO:
{
CZapitClient::CCurrentServiceInfo msgCurrentServiceInfo;
msgCurrentServiceInfo.onid = channel->getOriginalNetworkId();
msgCurrentServiceInfo.sid = channel->getServiceId();
msgCurrentServiceInfo.tsid = channel->getTransportStreamId();
msgCurrentServiceInfo.vpid = channel->getVideoPid();
msgCurrentServiceInfo.apid = channel->getAudioPid();
msgCurrentServiceInfo.vtxtpid = channel->getTeletextPid();
msgCurrentServiceInfo.pmtpid = channel->getPmtPid();
msgCurrentServiceInfo.pcrpid = channel->getPcrPid();
msgCurrentServiceInfo.tsfrequency = frontend->getFrequency();
if (frontend->getInfo()->type == FE_QPSK)
msgCurrentServiceInfo.polarisation = frontend->getPolarization();
else
msgCurrentServiceInfo.polarisation = 2;
msgCurrentServiceInfo.diseqc = channel->getDiSEqC();
CBasicServer::send_data(connfd, &msgCurrentServiceInfo, sizeof(msgCurrentServiceInfo));
break;
}

case CZapitMessages::CMD_GET_DELIVERY_SYSTEM:
{
CZapitMessages::responseDeliverySystem response;
switch (frontend->getInfo()->type) {
case FE_QAM:
response.system = DVB_C;
break;
case FE_QPSK:
response.system = DVB_S;
break;
case FE_OFDM:
response.system = DVB_T;
break;
default:
break;
}
CBasicServer::send_data(connfd, &response, sizeof(response));
break;
}

case CZapitMessages::CMD_GET_BOUQUETS:
{
CZapitMessages::commandGetBouquets msgGetBouquets;
CBasicServer::receive_data(connfd, &msgGetBouquets, sizeof(msgGetBouquets));
sendBouquets(connfd, msgGetBouquets.emptyBouquetsToo); // bouquet & channel number are already starting at 0!
break;
}

case CZapitMessages::CMD_GET_BOUQUET_CHANNELS:
{
CZapitMessages::commandGetBouquetChannels msgGetBouquetChannels;
CBasicServer::receive_data(connfd, &msgGetBouquetChannels, sizeof(msgGetBouquetChannels));
sendBouquetChannels(connfd, msgGetBouquetChannels.bouquet, msgGetBouquetChannels.mode); // bouquet & channel number are already starting at 0!
break;
}

case CZapitMessages::CMD_GET_CHANNELS:
{
CZapitMessages::commandGetChannels msgGetChannels;
CBasicServer::receive_data(connfd, &msgGetChannels, sizeof(msgGetChannels));
sendChannels(connfd, msgGetChannels.mode, msgGetChannels.order); // bouquet & channel number are already starting at 0!
break;
}

case CZapitMessages::CMD_GET_CURRENT_TP:
{
TP_params TP;
get_transponder(&TP);
INFO("current frequency: %lu", (long unsigned int)TP.feparams.frequency);
CBasicServer::send_data(connfd, &TP, sizeof(TP));
break;
}

case CZapitMessages::CMD_BQ_RESTORE:
{
CZapitMessages::responseCmd response;

bouquetManager->clearAll();
bouquetManager->loadBouquets();

response.cmd = CZapitMessages::CMD_READY;
CBasicServer::send_data(connfd, &response, sizeof(response));
break;
}

case CZapitMessages::CMD_REINIT_CHANNELS:
{
CZapitMessages::responseCmd response;
prepare_channels(frontend->getInfo()->type, diseqcType);
response.cmd = CZapitMessages::CMD_READY;
CBasicServer::send_data(connfd, &response, sizeof(response));
eventServer->sendEvent(CZapitClient::EVT_BOUQUETS_CHANGED, CEventServer::INITID_ZAPIT);
break;
}

case CZapitMessages::CMD_SCANSTART:
{
bool scan_mode;
CBasicServer::receive_data(connfd, &scan_mode, sizeof(scan_mode));

if (start_scan(scan_mode) == -1)
eventServer->sendEvent(CZapitClient::EVT_SCAN_FAILED, CEventServer::INITID_ZAPIT);
break;
}
case CZapitMessages::CMD_SCANSTOP:
if (scan_runs)
{
scan_clean();
}
break;

case CZapitMessages::CMD_SCAN_TP:
{
TP_params TP;
CBasicServer::receive_data(connfd, &TP, sizeof(TP));
transponder_list_t::iterator transponder = transponders.find(channel->getTransponderId());
if(!(TP.feparams.frequency > 0) && channel)
{

TP.feparams.frequency = transponder->second.feparams.frequency;
TP.feparams.u.qpsk.symbol_rate = transponder->second.feparams.u.qpsk.symbol_rate;
TP.feparams.u.qpsk.fec_inner = transponder->second.feparams.u.qpsk.fec_inner;
TP.polarization = transponder->second.polarization;
}
if(scanProviders.size()>0)
scanProviders.clear();

std::map<string, t_satellite_position>::iterator spos_it;
for (spos_it = satellitePositions.begin(); spos_it != satellitePositions.end(); spos_it++)
{
if(spos_it->second == channel->getSatellitePosition())
{
scanProviders[transponder->second.DiSEqC] = spos_it->first.c_str();
}
}
channel = 0;
TP.diseqc=transponder->second.DiSEqC;
bouquetManager->clearAll();
allchans.clear(); // <- this invalidates all bouquets, too!
stopPlayBack();
if(scan_transponder(&TP))
{
DBG("transponder scan ok");
}
prepare_channels(frontend->getInfo()->type, diseqcType);
DBG("channels reinit ok");
eventServer->sendEvent(CZapitClient::EVT_BOUQUETS_CHANGED, CEventServer::INITID_ZAPIT);
break;
}

case CZapitMessages::CMD_SCANREADY:
{
CZapitMessages::responseIsScanReady msgResponseIsScanReady;
msgResponseIsScanReady.satellite = curr_sat;
msgResponseIsScanReady.transponder = found_transponders;
msgResponseIsScanReady.processed_transponder = processed_transponders;
msgResponseIsScanReady.services = found_channels;
if (scan_runs > 0)
msgResponseIsScanReady.scanReady = false;
else
msgResponseIsScanReady.scanReady = true;
CBasicServer::send_data(connfd, &msgResponseIsScanReady, sizeof(msgResponseIsScanReady));
break;
}

case CZapitMessages::CMD_SCANGETSATLIST:
{
if (!scanInputParser)
{
parseScanInputXml();
if (!scanInputParser)
break;
}

uint32_t satlength;
char * satname;
xmlNodePtr search = xmlDocGetRootElement(scanInputParser)->xmlChildrenNode;
const char * frontendname = getFrontendName();
CZapitClient::responseGetSatelliteList sat;

if (frontendname != NULL)
while ((search = xmlGetNextOccurence(search, frontendname)) != NULL)
{
satname = xmlGetAttribute(search, "name");
strncpy(sat.satName, satname, 29);
sat.satPosition = satellitePositions[satname];
sat.motorPosition = motorPositions[sat.satPosition];
sat.satDiseqc = -1; /* FIXME */
satlength = sizeof(sat);
//printf("[zapit] sending %s, %d, %d\n", sat.satName, sat.satPosition, sat.motorPosition);
CBasicServer::send_data(connfd, &satlength, sizeof(satlength));
CBasicServer::send_data(connfd, (char *)&sat, satlength);
search = search->xmlNextNode;
}
satlength = SATNAMES_END_MARKER;
CBasicServer::send_data(connfd, &satlength, sizeof(satlength));
break;
}

case CZapitMessages::CMD_SCANSETSCANSATLIST:
{
CZapitClient::commandSetScanSatelliteList sat;
scanProviders.clear();
while (CBasicServer::receive_data(connfd, &sat, sizeof(sat))) {
DBG("adding %s (diseqc %d)", sat.satName, sat.diseqc);
scanProviders[sat.diseqc] = sat.satName;
}
break;
}

case CZapitMessages::CMD_SCANSETSCANMOTORPOSLIST:
{
CZapitClient::commandSetScanMotorPosList pos;
bool changed = false;
FILE * fd;

while (CBasicServer::receive_data(connfd, &pos, sizeof(pos)))
{
//printf("adding %d (motorPos %d)\n", pos.satPosition, pos.motorPos);
changed |= (motorPositions[pos.satPosition] != pos.motorPos);
motorPositions[pos.satPosition] = pos.motorPos;
}

if (changed)
{
// save to motor.conf
//printf("[zapit] saving motor.conf\n");
fd = fopen(MOTORCONFIGFILE, "w");
for (mpos_it = motorPositions.begin(); mpos_it != motorPositions.end(); mpos_it++)
{
//printf("[zapit] saving %d %d\n", mpos_it->first, mpos_it->second);
fprintf(fd, "%d %d\n", mpos_it->first, mpos_it->second);
}
fclose(fd);
chmod(MOTORCONFIGFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
break;
}

case CZapitMessages::CMD_SCANSETDISEQCTYPE:
{
CBasicServer::receive_data(connfd, &diseqcType, sizeof(diseqcType));
frontend->setDiseqcType(diseqcType);
DBG("set diseqc type %d", diseqcType);
break;
}

case CZapitMessages::CMD_SCANSETDISEQCREPEAT:
{
uint32_t repeats;
CBasicServer::receive_data(connfd, &repeats, sizeof(repeats));
frontend->setDiseqcRepeats(repeats);
DBG("set diseqc repeats to %d", repeats);
break;
}

case CZapitMessages::CMD_SCANSETBOUQUETMODE:
CBasicServer::receive_data(connfd, &bouquetMode, sizeof(bouquetMode));
break;

case CZapitMessages::CMD_SCANSETTYPE:
CBasicServer::receive_data(connfd, &scanType, sizeof(scanType));
break;

case CZapitMessages::CMD_SET_RECORD_MODE:
{
CZapitMessages::commandSetRecordMode msgSetRecordMode;
CBasicServer::receive_data(connfd, &msgSetRecordMode, sizeof(msgSetRecordMode));
if (msgSetRecordMode.activate)
setRecordMode();
else
unsetRecordMode();
break;
}

case CZapitMessages::CMD_GET_RECORD_MODE:
{
CZapitMessages::responseGetRecordModeState msgGetRecordModeState;
msgGetRecordModeState.activated = (currentMode & RECORD_MODE);
CBasicServer::send_data(connfd, &msgGetRecordModeState, sizeof(msgGetRecordModeState));
break;
}

case CZapitMessages::CMD_SB_GET_PLAYBACK_ACTIVE:
{
CZapitMessages::responseGetPlaybackState msgGetPlaybackState;
if (videoDecoder->getPlayState() == VIDEO_PLAYING)
msgGetPlaybackState.activated = 1;
else
msgGetPlaybackState.activated = 0;
CBasicServer::send_data(connfd, &msgGetPlaybackState, sizeof(msgGetPlaybackState));
break;
}

case CZapitMessages::CMD_BQ_ADD_BOUQUET:
{
char * name = CBasicServer::receive_string(connfd);
bouquetManager->addBouquet(name);
CBasicServer::delete_string(name);
break;
}

case CZapitMessages::CMD_BQ_DELETE_BOUQUET:
{
CZapitMessages::commandDeleteBouquet msgDeleteBouquet;
CBasicServer::receive_data(connfd, &msgDeleteBouquet, sizeof(msgDeleteBouquet)); // bouquet & channel number are already starting at 0!
bouquetManager->deleteBouquet(msgDeleteBouquet.bouquet);
break;
}

case CZapitMessages::CMD_BQ_RENAME_BOUQUET:
{
CZapitMessages::commandRenameBouquet msgRenameBouquet;
CBasicServer::receive_data(connfd, &msgRenameBouquet, sizeof(msgRenameBouquet)); // bouquet & channel number are already starting at 0!
char * name = CBasicServer::receive_string(connfd);
if (msgRenameBouquet.bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[msgRenameBouquet.bouquet]->Name = name;
CBasicServer::delete_string(name);
break;
}

case CZapitMessages::CMD_BQ_EXISTS_BOUQUET:
{
CZapitMessages::responseGeneralInteger responseInteger;

char * name = CBasicServer::receive_string(connfd);
responseInteger.number = bouquetManager->existsBouquet(name);
CBasicServer::delete_string(name);

CBasicServer::send_data(connfd, &responseInteger, sizeof(responseInteger)); // bouquet & channel number are already starting at 0!
break;
}

case CZapitMessages::CMD_BQ_EXISTS_CHANNEL_IN_BOUQUET:
{
CZapitMessages::commandExistsChannelInBouquet msgExistsChInBq;
CZapitMessages::responseGeneralTrueFalse responseBool;
CBasicServer::receive_data(connfd, &msgExistsChInBq, sizeof(msgExistsChInBq)); // bouquet & channel number are already starting at 0!
responseBool.status = bouquetManager->existsChannelInBouquet(msgExistsChInBq.bouquet, msgExistsChInBq.channel_id);
CBasicServer::send_data(connfd, &responseBool, sizeof(responseBool));
break;
}

case CZapitMessages::CMD_BQ_MOVE_BOUQUET:
{
CZapitMessages::commandMoveBouquet msgMoveBouquet;
CBasicServer::receive_data(connfd, &msgMoveBouquet, sizeof(msgMoveBouquet)); // bouquet & channel number are already starting at 0!
bouquetManager->moveBouquet(msgMoveBouquet.bouquet, msgMoveBouquet.newPos);
break;
}

case CZapitMessages::CMD_BQ_ADD_CHANNEL_TO_BOUQUET:
{
CZapitMessages::commandAddChannelToBouquet msgAddChannelToBouquet;
CBasicServer::receive_data(connfd, &msgAddChannelToBouquet, sizeof(msgAddChannelToBouquet)); // bouquet & channel number are already starting at 0!
addChannelToBouquet(msgAddChannelToBouquet.bouquet, msgAddChannelToBouquet.channel_id);
break;
}

case CZapitMessages::CMD_BQ_REMOVE_CHANNEL_FROM_BOUQUET:
{
CZapitMessages::commandRemoveChannelFromBouquet msgRemoveChannelFromBouquet;
CBasicServer::receive_data(connfd, &msgRemoveChannelFromBouquet, sizeof(msgRemoveChannelFromBouquet)); // bouquet & channel number are already starting at 0!
if (msgRemoveChannelFromBouquet.bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[msgRemoveChannelFromBouquet.bouquet]->removeService(msgRemoveChannelFromBouquet.channel_id);
break;
}

case CZapitMessages::CMD_BQ_MOVE_CHANNEL:
{
CZapitMessages::commandMoveChannel msgMoveChannel;
CBasicServer::receive_data(connfd, &msgMoveChannel, sizeof(msgMoveChannel)); // bouquet & channel number are already starting at 0!
if (msgMoveChannel.bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[msgMoveChannel.bouquet]->moveService(msgMoveChannel.oldPos, msgMoveChannel.newPos,
(((currentMode & RADIO_MODE) && msgMoveChannel.mode == CZapitClient::MODE_CURRENT)
|| (msgMoveChannel.mode==CZapitClient::MODE_RADIO)) ? 2 : 1);
break;
}

case CZapitMessages::CMD_BQ_SET_LOCKSTATE:
{
CZapitMessages::commandBouquetState msgBouquetLockState;
CBasicServer::receive_data(connfd, &msgBouquetLockState, sizeof(msgBouquetLockState)); // bouquet & channel number are already starting at 0!
if (msgBouquetLockState.bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[msgBouquetLockState.bouquet]->bLocked = msgBouquetLockState.state;
break;
}

case CZapitMessages::CMD_BQ_SET_HIDDENSTATE:
{
CZapitMessages::commandBouquetState msgBouquetHiddenState;
CBasicServer::receive_data(connfd, &msgBouquetHiddenState, sizeof(msgBouquetHiddenState)); // bouquet & channel number are already starting at 0!
if (msgBouquetHiddenState.bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[msgBouquetHiddenState.bouquet]->bHidden = msgBouquetHiddenState.state;
break;
}

case CZapitMessages::CMD_BQ_RENUM_CHANNELLIST:
bouquetManager->renumServices();
break;

case CZapitMessages::CMD_BQ_SAVE_BOUQUETS:
{
CZapitMessages::responseCmd response;

bouquetManager->saveBouquets();
bouquetManager->renumServices();

response.cmd = CZapitMessages::CMD_READY;
CBasicServer::send_data(connfd, &response, sizeof(response));

eventServer->sendEvent(CZapitClient::EVT_BOUQUETS_CHANGED, CEventServer::INITID_ZAPIT);

break;
}

case CZapitMessages::CMD_SET_PAL:
{
setVideoSystem_t(0);
break;
}

case CZapitMessages::CMD_SET_NTSC:
{
setVideoSystem_t(1);
break;
}

case CZapitMessages::CMD_SB_START_PLAYBACK:
playbackStopForced = false;
/* FIXME: nvod */
startPlayBack(channel);
break;

case CZapitMessages::CMD_SB_STOP_PLAYBACK:
stopPlayBack();
playbackStopForced = true;
break;

case CZapitMessages::CMD_SET_DISPLAY_FORMAT:
{
CZapitMessages::commandInt msg;
CBasicServer::receive_data(connfd, &msg, sizeof(msg));
videoDecoder->setCroppingMode((video_displayformat_t) msg.val);
break;
}

case CZapitMessages::CMD_SET_AUDIO_MODE:
{
CZapitMessages::commandInt msg;
CBasicServer::receive_data(connfd, &msg, sizeof(msg));
audioDecoder->setChannel((audio_channel_select_t) msg.val);
break;
}

case CZapitMessages::CMD_GETPIDS:
{
if (channel)
{
CZapitClient::responseGetOtherPIDs responseGetOtherPIDs;
responseGetOtherPIDs.vpid = channel->getVideoPid();
responseGetOtherPIDs.ecmpid = NONE; // TODO: remove
responseGetOtherPIDs.vtxtpid = channel->getTeletextPid();
responseGetOtherPIDs.pcrpid = channel->getPcrPid();
responseGetOtherPIDs.pmtpid = channel->getPmtPid();
responseGetOtherPIDs.selected_apid = channel->getAudioChannelIndex();
CBasicServer::send_data(connfd, &responseGetOtherPIDs, sizeof(responseGetOtherPIDs));
sendAPIDs(connfd);
}
break;
}

case CZapitMessages::CMD_GET_FE_SIGNAL:
{
CZapitClient::responseFESignal response_FEsig;

response_FEsig.sig = frontend->getSignalStrength();
response_FEsig.snr = frontend->getSignalNoiseRatio();
response_FEsig.ber = frontend->getBitErrorRate();

CBasicServer::send_data(connfd, &response_FEsig, sizeof(CZapitClient::responseFESignal));
break;
}

case CZapitMessages::CMD_SETSUBSERVICES:
{
CZapitClient::commandAddSubServices msgAddSubService;

while (CBasicServer::receive_data(connfd, &msgAddSubService, sizeof(msgAddSubService)))
{
t_original_network_id original_network_id = msgAddSubService.original_network_id;
t_service_id service_id = msgAddSubService.service_id;
nvodchannels.insert
(
std::pair <t_channel_id, CZapitChannel>
(
CREATE_CHANNEL_ID_FROM_SERVICE_ORIGINALNETWORK_TRANSPORTSTREAM_ID(msgAddSubService.service_id, msgAddSubService.original_network_id, msgAddSubService.transport_stream_id),
CZapitChannel
(
"NVOD",
service_id,
msgAddSubService.transport_stream_id,
original_network_id,
1,
channel->getDiSEqC(),
channel->getSatellitePosition()
)
)
);
}

current_is_nvod = true;
break;
}

case CZapitMessages::CMD_REGISTEREVENTS:
eventServer->registerEvent(connfd);
break;

case CZapitMessages::CMD_UNREGISTEREVENTS:
eventServer->unRegisterEvent(connfd);
break;

case CZapitMessages::CMD_MUTE:
{
CZapitMessages::commandBoolean msgBoolean;
CBasicServer::receive_data(connfd, &msgBoolean, sizeof(msgBoolean));
if (msgBoolean.truefalse)
audioDecoder->mute();
else
audioDecoder->unmute();
break;
}

case CZapitMessages::CMD_SET_VOLUME:
{
CZapitMessages::commandVolume msgVolume;
CBasicServer::receive_data(connfd, &msgVolume, sizeof(msgVolume));
audioDecoder->setVolume(msgVolume.left, msgVolume.right);
break;
}

case CZapitMessages::CMD_SET_STANDBY:
{
CZapitMessages::commandBoolean msgBoolean;
CBasicServer::receive_data(connfd, &msgBoolean, sizeof(msgBoolean));
if (msgBoolean.truefalse)
enterStandby();
else
leaveStandby();
break;
}

case CZapitMessages::CMD_NVOD_SUBSERVICE_NUM:
{
CZapitMessages::commandInt msg;
CBasicServer::receive_data(connfd, &msg, sizeof(msg));
select_nvod_subservice_num(msg.val);
break;
}

case CZapitMessages::CMD_SEND_MOTOR_COMMAND:
{
CZapitMessages::commandMotor msgMotor;
CBasicServer::receive_data(connfd, &msgMotor, sizeof(msgMotor));
printf("[zapit] received motor command: %x %x %x %x %x %x\n", msgMotor.cmdtype, msgMotor.address, msgMotor.cmd, msgMotor.num_parameters, msgMotor.param1, msgMotor.param2);
frontend->sendMotorCommand(msgMotor.cmdtype, msgMotor.address, msgMotor.cmd, msgMotor.num_parameters, msgMotor.param1, msgMotor.param2);
break;
}

case CZapitMessages::CMD_GET_CHANNEL_NAME:
{
t_channel_id requested_channel_id;
CZapitMessages::responseGetChannelName response;
CBasicServer::receive_data(connfd, &requested_channel_id, sizeof(requested_channel_id));
tallchans_iterator it = allchans.find(requested_channel_id);
if (it == allchans.end())
response.name[0] = 0;
else
strncpy(response.name, it->second.getName().c_str(), 30);

CBasicServer::send_data(connfd, &response, sizeof(response));
break;
}

case CZapitMessages::CMD_IS_TV_CHANNEL:
{
t_channel_id requested_channel_id;
CZapitMessages::responseGeneralTrueFalse response;
CBasicServer::receive_data(connfd, &requested_channel_id, sizeof(requested_channel_id));
tallchans_iterator it = allchans.find(requested_channel_id);
if (it == allchans.end())
/* if in doubt (i.e. unknown channel) answer yes for possible subservices */
response.status = true; //true == tv mode
else
/* FIXME: the following check is no even remotely accurate */
response.status = (it->second.getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE);

CBasicServer::send_data(connfd, &response, sizeof(response));
break;
}

case CZapitMessages::CMD_SET_AE_IEC_ON:
{
setIec(1);
break;
}

case CZapitMessages::CMD_SET_AE_IEC_OFF:
{
setIec(0);
break;
}

case CZapitMessages::CMD_GET_AE_IEC_STATE:
{
CZapitMessages::responseGeneralInteger responseInteger;
responseInteger.number = aviaExtDriver->iecState();
CBasicServer::send_data(connfd, &responseInteger, sizeof(responseInteger));
break;
}

case CZapitMessages::CMD_SET_AE_PLAYBACK_PES:
{
setDemuxMode(0);
break;
}

case CZapitMessages::CMD_SET_AE_PLAYBACK_SPTS:
{
setDemuxMode(1);
break;
}

case CZapitMessages::CMD_GET_AE_PLAYBACK_STATE:
{
CZapitMessages::responseGeneralInteger responseInteger;
responseInteger.number = aviaExtDriver->playbackState();
CBasicServer::send_data(connfd, &responseInteger, sizeof(responseInteger));
break;
}

default:
WARN("unknown command %d (version %d)", rmsg.cmd, CZapitMessages::ACTVERSION);
break;
}

DBG("cmd %d processed", rmsg.cmd);

return true;
}

/****************************************************************/
/* */
/* functions for new command handling via CZapitClient */
/* */
/* these functions should be encapsulated in a class CZapit */
/* */
/****************************************************************/

void addChannelToBouquet(const unsigned int bouquet, const t_channel_id channel_id)
{
DBG("addChannelToBouquet(%d, " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS ")", bouquet, channel_id);

CZapitChannel* chan = bouquetManager->findChannelByChannelID(channel_id);

if (chan != NULL)
if (bouquet < bouquetManager->Bouquets.size())
bouquetManager->Bouquets[bouquet]->addService(chan);
else
WARN("bouquet not found");
else
WARN("channel_id not found in channellist");
}

void sendBouquets(int connfd, const bool emptyBouquetsToo)
{
CZapitClient::responseGetBouquets msgBouquet;

for (uint i = 0; i < bouquetManager->Bouquets.size(); i++)
{
if (emptyBouquetsToo ||
((!bouquetManager->Bouquets->bHidden) &&
(((currentMode & RADIO_MODE) && !bouquetManager->Bouquets->radioChannels.empty()) ||
((currentMode & TV_MODE) && !bouquetManager->Bouquets->tvChannels.empty()))))
{
// ATTENTION: in RECORD_MODE empty bouquets are not send!
if ((!(currentMode & RECORD_MODE)) ||
((channel != NULL) &&
(((currentMode & RADIO_MODE) && (bouquetManager->Bouquets->recModeRadioSize(channel->getTransponderId()) > 0)) ||
((currentMode & TV_MODE) && (bouquetManager->Bouquets->recModeTVSize (channel->getTransponderId()) > 0)))))
{
msgBouquet.bouquet_nr = i;
strncpy(msgBouquet.name, bouquetManager->Bouquets->Name.c_str(), 30);
msgBouquet.locked = bouquetManager->Bouquets->bLocked;
msgBouquet.hidden = bouquetManager->Bouquets->bHidden;
if (CBasicServer::send_data(connfd, &msgBouquet, sizeof(msgBouquet)) == false)
{
ERROR("could not send any return");
return;
}
}
}
}
msgBouquet.bouquet_nr = RESPONSE_GET_BOUQUETS_END_MARKER;
if (CBasicServer::send_data(connfd, &msgBouquet, sizeof(msgBouquet)) == false)
{
ERROR("could not send end marker");
return;
}
}

bool send_data_count(const int connfd, const int data_count)
{
CZapitMessages::responseGeneralInteger responseInteger;
responseInteger.number = data_count;
if (CBasicServer::send_data(connfd, &responseInteger, sizeof(responseInteger)) == false)
{
ERROR("could not send any return");
return false;
}
return true;
}

void internalSendChannels(int connfd, ChannelList* channels, const unsigned int first_channel_nr)
{
int data_count = channels->size();
if (currentMode & RECORD_MODE)
{
for (uint32_t i = 0; i < channels->size(); i++)
if ((*channels)->getTransponderId() != channel->getTransponderId())
data_count--;
}

if (!send_data_count(connfd, data_count))
return;

for (uint32_t i = 0; i < channels->size();i++)
{
if ((currentMode & RECORD_MODE) && ((*channels)->getTransponderId() != channel->getTransponderId()))
continue;

CZapitClient::responseGetBouquetChannels response;
strncpy(response.name, ((*channels)[i]->getName()).c_str(), 30);
response.satellitePosition = (*channels)[i]->getSatellitePosition();
response.channel_id = (*channels)[i]->getChannelID();
response.nr = first_channel_nr + i;
response.service_type = (*channels)[i]->getServiceType();

if (CBasicServer::send_data(connfd, &response, sizeof(response)) == false)
{
ERROR("could not send any return");
return;
}
}
}

void sendAPIDs(int connfd)
{
if (!send_data_count(connfd, channel->getAudioChannelCount()))
return;

for (uint32_t i = 0; i < channel->getAudioChannelCount(); i++)
{
CZapitClient::responseGetAPIDs response;
response.pid = channel->getAudioPid(i);
strncpy(response.desc, channel->getAudioChannel(i)->description.c_str(), 25);
response.is_ac3 = channel->getAudioChannel(i)->isAc3;
response.component_tag = channel->getAudioChannel(i)->componentTag;

if (CBasicServer::send_data(connfd, &response, sizeof(response)) == false)
{
ERROR("could not send any return");
return;
}
}
}


void sendBouquetChannels(int connfd, const unsigned int bouquet, const CZapitClient::channelsMode mode)
{
if (bouquet >= bouquetManager->Bouquets.size())
{
WARN("invalid bouquet number: %d", bouquet);
return;
}

if (((currentMode & RADIO_MODE) && (mode == CZapitClient::MODE_CURRENT)) || (mode == CZapitClient::MODE_RADIO))
internalSendChannels(connfd, &(bouquetManager->Bouquets[bouquet]->radioChannels), bouquetManager->radioChannelsBegin().getNrofFirstChannelofBouquet(bouquet));
else
internalSendChannels(connfd, &(bouquetManager->Bouquets[bouquet]->tvChannels), bouquetManager->tvChannelsBegin().getNrofFirstChannelofBouquet(bouquet));
}

void sendChannels(int connfd, const CZapitClient::channelsMode mode, const CZapitClient::channelsOrder order)
{
ChannelList channels;

if (order == CZapitClient::SORT_BOUQUET)
{
CBouquetManager::ChannelIterator cit = (((currentMode & RADIO_MODE) && (mode == CZapitClient::MODE_CURRENT)) || (mode==CZapitClient::MODE_RADIO)) ? bouquetManager->radioChannelsBegin() : bouquetManager->tvChannelsBegin();
for (; !(cit.EndOfChannels()); cit++)
channels.push_back(*cit);
}
else if (order == CZapitClient::SORT_ALPHA) // ATTENTION: in this case response.nr does not return the actual number of the channel for zapping!
{
if (((currentMode & RADIO_MODE) && (mode == CZapitClient::MODE_CURRENT)) || (mode==CZapitClient::MODE_RADIO))
{
for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++)
if (it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE)
channels.push_back(&(it->second));
}
else
{
for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++)
if (it->second.getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE)
channels.push_back(&(it->second));
}
sort(channels.begin(), channels.end(), CmpChannelByChName());
}

internalSendChannels(connfd, &channels, 0);
}

int startPlayBack(CZapitChannel *thisChannel)
{
bool have_pcr = false;
bool have_audio = false;
bool have_video = false;
bool have_teletext = false;

if ((playbackStopForced == true) || (!thisChannel))
return -1;

if (thisChannel->getPcrPid() != 0)
have_pcr = true;
if (thisChannel->getAudioPid() != NONE)
have_audio = true;
if ((thisChannel->getVideoPid() != NONE) && (currentMode & TV_MODE))
have_video = true;
if (thisChannel->getTeletextPid() != 0)
have_teletext = true;

if ((!have_audio) && (!have_video) && (!have_teletext))
return -1;

/* set demux filters */
if (have_pcr) {
if (!pcrDemux)
pcrDemux = new CDemux();
if (pcrDemux->pesFilter(thisChannel->getPcrPid(), DMX_OUT_DECODER, DMX_PES_PCR) < 0)
return -1;
if (pcrDemux->start() < 0)
return -1;
}
if (have_audio) {
if (!audioDemux)
audioDemux = new CDemux();
if (audioDemux->pesFilter(thisChannel->getAudioPid(), DMX_OUT_DECODER, DMX_PES_AUDIO) < 0)
return -1;
if (audioDemux->start() < 0)
return -1;
}
if (have_video) {
if (!videoDemux)
videoDemux = new CDemux();
if (videoDemux->pesFilter(thisChannel->getVideoPid(), DMX_OUT_DECODER, DMX_PES_VIDEO) < 0)
return -1;
if (videoDemux->start() < 0)
return -1;
}
if (have_teletext) {
if (!teletextDemux)
teletextDemux = new CDemux();
if (teletextDemux->pesFilter(thisChannel->getTeletextPid(), DMX_OUT_DECODER, DMX_PES_TELETEXT) < 0)
return -1;
if (teletextDemux->start() < 0)
return -1;
}

/* start video */
if (have_video) {
videoDecoder->setSource(VIDEO_SOURCE_DEMUX);
videoDecoder->start();
}

/* select audio output and start audio */
if (have_audio) {
if (thisChannel->getAudioChannel()->isAc3)
audioDecoder->enableBypass();
else
audioDecoder->disableBypass();

audioDecoder->setSource(AUDIO_SOURCE_DEMUX);
audioDecoder->start();
}

return 0;
}

int stopPlayBack(void)
{
if (playbackStopForced)
return -1;

if (teletextDemux)
teletextDemux->stop();
if (videoDemux)
videoDemux->stop();
if (audioDemux)
audioDemux->stop();
if (pcrDemux)
pcrDemux->stop();
if (audioDecoder)
audioDecoder->stop();
if (videoDecoder)
videoDecoder->stop();

return 0;
}

void setVideoSystem_t(int video_system)
{
if (video_system == 0)
videoDecoder->setVideoSystem(PAL);
else
videoDecoder->setVideoSystem(NTSC);
}

void setIec(int iec_active)
{
if (iec_active == 0)
aviaExtDriver->iecOff();
else
aviaExtDriver->iecOn();
}

void setDemuxMode(int demux_mode)
{
if (demux_mode == 0)
aviaExtDriver->playbackPES();
else
aviaExtDriver->playbackSPTS();

if ((videoDecoder->getPlayState() == VIDEO_PLAYING) && (channel)) {
//printf("[zapit] restarting playback after changing demux mode\n");
stopPlayBack();
playbackStopForced = true;
sleep(1);
playbackStopForced = false;
startPlayBack(channel);
}
}

void enterStandby(void)
{
if (standby) {
sleep(1);
return;
}

standby = true;

saveSettings(true);
stopPlayBack();

if (audioDemux) {
delete audioDemux;
audioDemux = NULL;
}
if (pcrDemux) {
delete pcrDemux;
pcrDemux = NULL;
}
if (teletextDemux) {
delete teletextDemux;
teletextDemux = NULL;
}
if (videoDemux) {
delete videoDemux;
videoDemux = NULL;
}
if (audioDecoder) {
delete audioDecoder;
audioDecoder = NULL;
}
if (cam) {
delete cam;
cam = NULL;
}
if (frontend) {
delete frontend;
frontend = NULL;
}
if (videoDecoder) {
delete videoDecoder;
videoDecoder = NULL;
}

tuned_transponder_id = TRANSPONDER_ID_NOT_TUNED;
}

void leaveStandby(void)
{
if (!audioDecoder) {
audioDecoder = new CAudio();
audioDecoder->unmute();
}
if (!cam) {
cam = new CCam();
}
if (!frontend) {
frontend = new CFrontend();
}
if (!videoDecoder) {
videoDecoder = new CVideo();
}
if (!aviaExtDriver) {
aviaExtDriver = new CAViAext();
}

frontend->setCurrentSatellitePosition(config.getInt32("lastSatellitePosition", 192));
frontend->setDiseqcRepeats(config.getInt32("diseqcRepeats", 0));
motorRotationSpeed = config.getInt32("motorRotationSpeed", 18); // default: 1.8 degrees per second
diseqcType = (diseqc_t)config.getInt32("diseqcType", NO_DISEQC);
frontend->setDiseqcType(diseqcType);

for (unsigned int i = 0; i < MAX_LNBS; i++) {
char tmp[16];
sprintf(tmp, "lnb%d_OffsetLow", i);
frontend->setLnbOffset(false, i, config.getInt32(tmp, 9750000));
sprintf(tmp, "lnb%d_OffsetHigh", i);
frontend->setLnbOffset(true, i, config.getInt32(tmp, 10600000));
}

if (channel)
zapit(channel->getChannelID(), current_is_nvod, 0);

standby = false;
}

unsigned zapTo(const unsigned int bouquet, const unsigned int channel)
{
if (bouquet >= bouquetManager->Bouquets.size()) {
WARN("Invalid bouquet %d", bouquet);
return CZapitClient::ZAP_INVALID_PARAM;
}

ChannelList *channels;

if (currentMode & RADIO_MODE)
channels = &(bouquetManager->Bouquets[bouquet]->radioChannels);
else
channels = &(bouquetManager->Bouquets[bouquet]->tvChannels);

if (channel >= channels->size()) {
WARN("Invalid channel %d in bouquet %d", channel, bouquet);
return CZapitClient::ZAP_INVALID_PARAM;
}

return zapTo_ChannelID((*channels)[channel]->getChannelID(), false);
}

unsigned int zapTo_ChannelID(t_channel_id channel_id, bool isSubService)
{
unsigned int result = 0;

if (zapit(channel_id, isSubService, 0) < 0)
{
eventServer->sendEvent((isSubService ? CZapitClient::EVT_ZAP_SUB_FAILED : CZapitClient::EVT_ZAP_FAILED), CEventServer::INITID_ZAPIT, &channel_id, sizeof(channel_id));
return result;
}

result |= CZapitClient::ZAP_OK;

if (isSubService)
{
eventServer->sendEvent(CZapitClient::EVT_ZAP_SUB_COMPLETE, CEventServer::INITID_ZAPIT, &channel_id, sizeof(channel_id));
}
else if (current_is_nvod)
{
eventServer->sendEvent(CZapitClient::EVT_ZAP_COMPLETE_IS_NVOD, CEventServer::INITID_ZAPIT, &channel_id, sizeof(channel_id));
result |= CZapitClient::ZAP_IS_NVOD;
}
else
eventServer->sendEvent(CZapitClient::EVT_ZAP_COMPLETE, CEventServer::INITID_ZAPIT, &channel_id, sizeof(channel_id));

return result;
}

unsigned zapTo(const unsigned int channel)
{
CBouquetManager::ChannelIterator cit = ((currentMode & RADIO_MODE) ? bouquetManager->radioChannelsBegin() : bouquetManager->tvChannelsBegin()).FindChannelNr(channel);
if (!(cit.EndOfChannels()))
return zapTo_ChannelID((*cit)->getChannelID(), false);
else
return 0;
}

void signal_handler(int signum)
{
switch (signum) {
case SIGUSR1:
debug = !debug;
break;
default:
CZapitClient zapit;
zapit.shutdown();
break;
}
}

int main(int argc, char **argv)
{
fprintf(stdout, "$Id: zapit.cpp,v 1.370 2005/03/14 19:58:48 mws Exp $\n");

for (int i = 1; i < argc ; i++) {
if (!strcmp(argv[i], "-d")) {
debug = true;
}
else if (!strcmp(argv[i], "-q")) {
/* don't say anything */
int fd;

close(STDOUT_FILENO);
if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO)
close(fd);

close(STDERR_FILENO);
if ((fd = open("/dev/null", O_WRONLY)) != STDERR_FILENO)
close(fd);
}
else if (!strcmp(argv[i], "-u")) {
update_pmt=true;
printf("[zapit] PMT update enabled\n");
}
else {
fprintf(stderr,
"Usage: %s [-d] [-q]\n"
"-d : debug mode\n"
"-q : quiet mode\n"
"-u : enable update on PMT change\n"
"\n"
"Keys in config file " CONFIGFILE ":\n"
"saveLastChannel" ", "
"lastChannelMode" ", "
"lastChannelRadio" ", "
"lastChannelTV" ", "
"lastSatellitePosition" ", "
"writeChannelsNames" ", "
"makeRemainingChannelsBouquet" ", "
"diseqcRepeats" ", "
"diseqcType" ", "
"motorRotationSpeed" ", "
"lnb0_OffsetLow" ", ..., " "lnb63_OffsetLow" ", "
"lnb0_OffsetHigh" ", ..., " "lnb63_OffsetHigh" "."
"\n", argv[0]);
return EXIT_FAILURE;
}
}

scan_runs = 0;
found_channels = 0;
curr_sat = -1;

/* load configuration or set defaults if no configuration file exists */
if (!config.loadConfig(CONFIGFILE))
WARN("%s not found", CONFIGFILE);

/* create bouquet manager */
bouquetManager = new CBouquetManager();

lastChannelRadio = config.getInt32("lastChannelRadio", 0);
lastChannelTV = config.getInt32("lastChannelTV", 0);

if (config.getInt32("lastChannelMode", 0))
setRadioMode();
else
setTVMode();

if (!frontend)
frontend = new CFrontend();

diseqcType = (diseqc_t)config.getInt32("diseqcType", NO_DISEQC);
if (prepare_channels(frontend->getInfo()->type, diseqcType) < 0)
WARN("error parsing services");
else
INFO("channels have been loaded succesfully");

signal(SIGHUP, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGUSR1, signal_handler);

CBasicServer zapit_server;

if (!zapit_server.prepare(ZAPIT_UDS_NAME))
return -1;

if (!debug)
switch (fork()) {
case -1: /* can't fork */
ERROR("fork");
return -1;
case 0: /* child, process becomes a daemon */
if (setsid() == -1) {
ERROR("setsid");
return -1;
}
break;
default: /* parent returns to calling process */
return 0;
}

// create eventServer
eventServer = new CEventServer;

leaveStandby();

if (update_pmt) {
while (zapit_server.run(parse_command, CZapitMessages::ACTVERSION, true)) {
struct pollfd pfd;

if (pmt_update_fd != -1) {
pfd.fd = pmt_update_fd;
pfd.events = (POLLIN | POLLPRI);
if (poll(&pfd, 1, 0) > 0) {
if (pfd.fd == pmt_update_fd)
zapit(channel->getChannelID(), current_is_nvod, 0);
}
}
/* yuck, don't waste that much cpu time :) */
usleep(0);
}
}
else {
zapit_server.run(parse_command, CZapitMessages::ACTVERSION);
}

enterStandby();

if (scanInputParser)
xmlFreeDoc(scanInputParser);

delete bouquetManager;
delete eventServer;

INFO("shutdown complete");

return 0;
}
lollyxy
Interessierter
Interessierter
Beiträge: 51
Registriert: Donnerstag 17. Juni 2004, 12:26

Beitrag von lollyxy »

Ist bestimmt nur ein banaler Fehler

-c -o zapit.o `test -f 'zapit.cpp' || echo './'`zapit.cpp; \
then mv -f ".deps/zapit.Tpo" ".deps/zapit.Po"; \
else rm -f ".deps/zapit.Tpo"; exit 1; \
fi
zapit.cpp: In function `void saveSettings(bool)':
zapit.cpp:188: error: `unsig' undeclared (first use this function)
zapit.cpp:188: error: (Each undeclared identifier is reported only once for
each function it appears in.)
zapit.cpp:188: error: parse error before `short'
zapit.cpp:189: error: `audio_map_it' undeclared (first use this function)
make[4]: *** [zapit.o] Fehler 1
make[4]: Leaving directory `/home/dbox/tuxbox-cvs/apps/dvb/zapit/src'
make[3]: *** [all-recursive] Fehler 1
make[3]: Leaving directory `/home/dbox/tuxbox-cvs/apps/dvb/zapit/src'
make[2]: *** [all-recursive] Fehler 1
make[2]: Leaving directory `/home/dbox/tuxbox-cvs/apps/dvb/zapit'
make[1]: *** [all] Fehler 2
make[1]: Leaving directory `/home/dbox/tuxbox-cvs/apps/dvb/zapit'
make: *** [.deps/zapit] Fehler 2
Barf
Developer
Beiträge: 1475
Registriert: Dienstag 4. Februar 2003, 22:02

Beitrag von Barf »

@lollyxy:

Ich will dich nicht verletzen, aber so hier ist es:

- Der Patch appliziert. Die so gepatchte zapit.cpp kompiliert korrekt.
- Das eine von dir erstellte "C++"-File (die erheblich abweicht) nicht kompiliert ist nicht ein Thema dieses Forums.

PS.

Code: Alles auswählen

patch zapit.cpp < zapit.cpp-patch-2005-02-20
lollyxy
Interessierter
Interessierter
Beiträge: 51
Registriert: Donnerstag 17. Juni 2004, 12:26

Beitrag von lollyxy »

Das ist eine zapit.cpp aus dem aktuellen cvs. Die diff von deiner Page habe ich eingebaut mehr nicht. :gruebel:
Habe das reingeschoben an den Stellen. Ist von deiner Page.

-- zapit.cpp-1.367 2005-02-20 11:00:38.000000000 +0100
+++ zapit.cpp 2005-02-20 11:10:40.000000000 +0100
@@ -22,6 +22,18 @@
*
*/

+/*
+ Options:
+ -d Debugmode: Don't fork, additionally generate debugging messages
+
+ -q Be quiet.
+
+ Signal handling:
+ SIGTERM, SIGHUP: Terminates zapit (gracefully)
+ SIGUSR1: Toggles debug mode
+*/
+
+
/* system headers */
#include <csignal>
#include <fcntl.h>
@@ -33,6 +45,10 @@
#include <config.h>
#endif

+// AudioPIDs per channel are saved here between sessions.
+// define to /dev/null to disable
+#define AUDIO_CONFIG_FILE "/var/tuxbox/config/zapit/audioPIDs.data"
+
/* tuxbox headers */
#include <configfile.h>
#include <connection/basicserver.h>
@@ -81,6 +97,9 @@
CDemux *teletextDemux = NULL;
CDemux *videoDemux = NULL;

+// This associative array holds the last selected AudioPid for each channel
+map<t_channel_id, unsigned short> audio_map;
+
/* current zapit mode */
enum {
TV_MODE = 0x01,
@@ -161,11 +180,36 @@

if (config.getModifiedFlag())
config.saveConfig(CONFIGFILE);
+ FILE *audio_config_file = fopen(AUDIO_CONFIG_FILE, "w");
+ if (audio_config_file) {
+ for (map<t_channel_id, unsigned short>::iterator audio_map_it = audio_map.begin();
+ audio_map_it != audio_map.end();
+ audio_map_it++) {
+ fwrite(&(audio_map_it->first), sizeof(t_channel_id), 1,
+ audio_config_file);
+ fwrite(&(audio_map_it->second), sizeof(unsigned short), 1,
+ audio_config_file);
+ }
+ fclose(audio_config_file);
+ }
}
}

CZapitClient::responseGetLastChannel load_settings(void)
{
+ FILE *audio_config_file = fopen(AUDIO_CONFIG_FILE, "r");
+ if (audio_config_file) {
+ t_channel_id chan;
+ unsigned short apid;
+ while (! feof(audio_config_file)) {
+ fread(&chan, sizeof(t_channel_id), 1, audio_config_file);
+ fread(&apid, sizeof(unsigned short), 1, audio_config_file);
+ //printf("**** Old channelinfo: %d %d\n", (int) chan, (int) apid);
+ audio_map[chan] = apid;
+ }
+ fclose(audio_config_file);
+ }
+
CZapitClient::responseGetLastChannel lastchannel;

if (currentMode & RADIO_MODE)
@@ -195,12 +239,23 @@
static int pmt_update_fd = -1;
static bool update_pmt = false;

+void
+remember_selected_audio()
+{
+ if (channel) {
+ audio_map[channel->getServiceId()] = channel->getAudioPid();
+ DBG("*** Remembering apid = %d for channel (service-id) = %d", channel->getAudioPid(), channel->getServiceId());
+ }
+}
+
int zapit(const t_channel_id channel_id, bool in_nvod, transponder_id_t transponder_id)
{
bool transponder_change;
tallchans_iterator cit;
transponder_id_t current_transponder_id;

+ remember_selected_audio();
+
DBG("tuned_transponder_id: " PRINTF_TRANSPONDER_ID_TYPE, tuned_transponder_id);

if (transponder_id == TRANSPONDER_ID_NOT_TUNED) /* usual zap */
@@ -344,7 +399,7 @@
failed = true;
}

- thisChannel->setAudioChannel(audioChannel);
+ thisChannel->setAudioChannel(audioChannel);

if ((!failed) && (thisChannel->getAudioPid() == NONE) && (thisChannel->getVideoPid() == NONE)) {
WARN("neither audio nor video pid found");
@@ -364,6 +419,18 @@
else
thisChannel->getCaPmt()->ca_pmt_list_management = 0x04;

+ DBG("***Now trying to get audio right: %d\t%d\t%d\t%d",
+ thisChannel->getAudioChannelCount(),
+ thisChannel->getAudioChannel(0)->pid,
+ thisChannel->getServiceId(),
+ audio_map[thisChannel->getServiceId()]);
+ for (int i = 0; i < thisChannel->getAudioChannelCount(); i++) {
+ if (thisChannel->getAudioChannel(i)->pid == audio_map[thisChannel->getServiceId()]) {
+ DBG("***** Setting audio!\n");
+ thisChannel->setAudioChannel(i);
+ }
+ }
+
startPlayBack(thisChannel);
cam->setCaPmt(thisChannel->getCaPmt());
saveSettings(false);
@@ -413,6 +480,7 @@

/* update current channel */
channel->setAudioChannel(index);
+ remember_selected_audio();

/* set bypass mode */
CZapitAudioChannel *currentAudioChannel = channel->getAudioChannel();


Sollte ich da was falsch verstanden haben dann sorry. Bin nicht so der crack sonst würde ich vielleicht in deinen Augen nicht solche blöden FRagen stellen. Seis drum danke für die nicht Hilfe.