00001 #include <unistd.h>
00002
00003 #include <qapplication.h>
00004 #include <qsqldatabase.h>
00005 #include <qstring.h>
00006 #include <qregexp.h>
00007 #include <qdir.h>
00008
00009 #include "tv_play.h"
00010 #include "programinfo.h"
00011
00012 #include "libmyth/exitcodes.h"
00013 #include "libmyth/mythcontext.h"
00014 #include "libmyth/mythdbcon.h"
00015 #include "libmyth/mythdialogs.h"
00016 #include "libmyth/compat.h"
00017 #include "audiopulseutil.h"
00018
00019 #include <iostream>
00020 using namespace std;
00021
00022 static void *run_priv_thread(void *data)
00023 {
00024 (void)data;
00025 while (true)
00026 {
00027 gContext->waitPrivRequest();
00028
00029 for (MythPrivRequest req = gContext->popPrivRequest();
00030 true; req = gContext->popPrivRequest())
00031 {
00032 bool done = false;
00033
00034 switch (req.getType())
00035 {
00036 case MythPrivRequest::MythRealtime:
00037 {
00038 pthread_t *target_thread = (pthread_t *)(req.getData());
00039
00040 struct sched_param sp = {1};
00041 if (target_thread)
00042 {
00043 int status = pthread_setschedparam(
00044 *target_thread, SCHED_FIFO, &sp);
00045 if (status)
00046 {
00047
00048 VERBOSE(VB_GENERAL, "Realtime priority would require SUID as root.");
00049 }
00050 else
00051 VERBOSE(VB_GENERAL, "Using realtime priority.");
00052 }
00053 else
00054 {
00055 VERBOSE(VB_IMPORTANT, "Unexpected NULL thread ptr "
00056 "for MythPrivRequest::MythRealtime");
00057 }
00058 }
00059 break;
00060 case MythPrivRequest::MythExit:
00061 pthread_exit(NULL);
00062 break;
00063 case MythPrivRequest::PrivEnd:
00064 done = true;
00065 break;
00066 }
00067 if (done)
00068 break;
00069 }
00070 }
00071 return NULL;
00072 }
00073
00074 int main(int argc, char *argv[])
00075 {
00076 QString geometry = QString::null;
00077 QString display = QString::null;
00078 #ifdef USING_X11
00079
00080
00081 for(int argpos = 1; argpos + 1 < argc; ++argpos)
00082 {
00083 if (!strcmp(argv[argpos],"-geometry"))
00084 geometry = argv[argpos+1];
00085 else if (!strcmp(argv[argpos],"-display"))
00086 display = argv[argpos+1];
00087 }
00088 #endif
00089
00090 QApplication a(argc, argv);
00091
00092 print_verbose_messages |= VB_PLAYBACK | VB_LIBAV;
00093
00094 QMap<QString, QString> settingsOverride;
00095 int argpos = 1;
00096 QString filename = "";
00097
00098 while (argpos < a.argc())
00099 {
00100 if (!strcmp(a.argv()[argpos],"-v") ||
00101 !strcmp(a.argv()[argpos],"--verbose"))
00102 {
00103 if ((a.argc() - 1) > argpos)
00104 {
00105 if (parse_verbose_arg(a.argv()[argpos+1]) ==
00106 GENERIC_EXIT_INVALID_CMDLINE)
00107 return GENERIC_EXIT_INVALID_CMDLINE;
00108
00109 ++argpos;
00110 }
00111 else
00112 {
00113 VERBOSE(VB_IMPORTANT,
00114 "Missing argument to -v/--verbose option");
00115 return COMMFLAG_EXIT_INVALID_CMDLINE;
00116 }
00117 }
00118 else if (!strcmp(a.argv()[argpos],"-O") ||
00119 !strcmp(a.argv()[argpos],"--override-setting"))
00120 {
00121 if ((a.argc() - 1) > argpos)
00122 {
00123 QString tmpArg = a.argv()[argpos+1];
00124 if (tmpArg.startsWith("-"))
00125 {
00126 cerr << "Invalid or missing argument to "
00127 "-O/--override-setting option\n";
00128 return BACKEND_EXIT_INVALID_CMDLINE;
00129 }
00130
00131 QStringList pairs = QStringList::split(",", tmpArg);
00132 for (unsigned int index = 0; index < pairs.size(); ++index)
00133 {
00134 QStringList tokens = QStringList::split("=", pairs[index]);
00135 tokens[0].replace(QRegExp("^[\"']"), "");
00136 tokens[0].replace(QRegExp("[\"']$"), "");
00137 tokens[1].replace(QRegExp("^[\"']"), "");
00138 tokens[1].replace(QRegExp("[\"']$"), "");
00139 settingsOverride[tokens[0]] = tokens[1];
00140 }
00141 }
00142 else
00143 {
00144 cerr << "Invalid or missing argument to -O/--override-setting "
00145 "option\n";
00146 return GENERIC_EXIT_INVALID_CMDLINE;
00147 }
00148
00149 ++argpos;
00150 }
00151 else if (!strcmp(a.argv()[argpos],"-display") ||
00152 !strcmp(a.argv()[argpos],"--display"))
00153 {
00154 if (a.argc()-1 > argpos)
00155 {
00156 display = a.argv()[argpos+1];
00157 if (display.startsWith("-"))
00158 {
00159 cerr << "Invalid or missing argument to -display option\n";
00160 return FRONTEND_EXIT_INVALID_CMDLINE;
00161 }
00162 else
00163 ++argpos;
00164 }
00165 else
00166 {
00167 cerr << "Missing argument to -display option\n";
00168 return FRONTEND_EXIT_INVALID_CMDLINE;
00169 }
00170 }
00171 else if (!strcmp(a.argv()[argpos],"-geometry") ||
00172 !strcmp(a.argv()[argpos],"--geometry"))
00173 {
00174 if (a.argc()-1 > argpos)
00175 {
00176 geometry = a.argv()[argpos+1];
00177 if (geometry.startsWith("-"))
00178 {
00179 cerr << "Invalid or missing argument to -geometry option\n";
00180 return FRONTEND_EXIT_INVALID_CMDLINE;
00181 }
00182 else
00183 ++argpos;
00184 }
00185 else
00186 {
00187 cerr << "Missing argument to -geometry option\n";
00188 return FRONTEND_EXIT_INVALID_CMDLINE;
00189 }
00190 }
00191 else if (a.argv()[argpos][0] != '-')
00192 {
00193 filename = a.argv()[argpos];
00194 }
00195
00196 ++argpos;
00197 }
00198
00199 if (!display.isEmpty())
00200 {
00201 gContext->SetX11Display(display);
00202 }
00203
00204 gContext = NULL;
00205 gContext = new MythContext(MYTH_BINARY_VERSION);
00206 if (!gContext->Init())
00207 {
00208 VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
00209 return TV_EXIT_NO_MYTHCONTEXT;
00210 }
00211
00212 if (!geometry.isEmpty() && !gContext->ParseGeometryOverride(geometry))
00213 {
00214 VERBOSE(VB_IMPORTANT,
00215 QString("Illegal -geometry argument '%1' (ignored)")
00216 .arg(geometry));
00217 }
00218
00219 if (settingsOverride.size())
00220 {
00221 QMap<QString, QString>::iterator it;
00222 for (it = settingsOverride.begin(); it != settingsOverride.end(); ++it)
00223 {
00224 VERBOSE(VB_IMPORTANT, QString("Setting '%1' being forced to '%2'")
00225 .arg(it.key()).arg(it.data()));
00226 gContext->OverrideSettingForSession(it.key(), it.data());
00227 }
00228 }
00229
00230
00231 pthread_t priv_thread;
00232 bool priv_thread_created = true;
00233
00234 int status = pthread_create(&priv_thread, NULL, run_priv_thread, NULL);
00235 if (status)
00236 {
00237 VERBOSE(VB_IMPORTANT, QString("Warning: ") +
00238 "Failed to create priveledged thread." + ENO);
00239 priv_thread_created = false;
00240 }
00241 setuid(getuid());
00242
00243 QString themename = gContext->GetSetting("Theme");
00244 QString themedir = gContext->FindThemeDir(themename);
00245 if (themedir == "")
00246 {
00247 QString msg = QString("Fatal Error: Couldn't find theme '%1'.")
00248 .arg(themename);
00249 VERBOSE(VB_IMPORTANT, msg);
00250 return TV_EXIT_NO_THEME;
00251 }
00252
00253 gContext->LoadQtConfig();
00254
00255 int pa_ret = pulseaudio_handle_startup();
00256 if (pa_ret != GENERIC_EXIT_OK)
00257 return pa_ret;
00258
00259 #if defined(Q_OS_MACX)
00260
00261 #else
00262 QString auddevice = gContext->GetSetting("AudioOutputDevice");
00263 if (auddevice == "" || auddevice == QString::null)
00264 {
00265 VERBOSE(VB_IMPORTANT, "Fatal Error: Audio not configured, you need "
00266 "to run 'mythfrontend', not 'mythtv'.");
00267 return TV_EXIT_NO_AUDIO;
00268 }
00269 #endif
00270
00271 MythMainWindow *mainWindow = GetMythMainWindow();
00272 mainWindow->Init();
00273 gContext->SetMainWindow(mainWindow);
00274
00275 TV::InitKeys();
00276
00277 TV *tv = new TV();
00278 if (!tv->Init())
00279 {
00280 VERBOSE(VB_IMPORTANT, "Fatal Error: Could not initializing TV class.");
00281 return TV_EXIT_NO_TV;
00282 }
00283
00284 ProgramInfo *pginfo = NULL;
00285
00286 if ((filename != "") &&
00287 ((pginfo = ProgramInfo::GetProgramFromBasename(filename)) == NULL))
00288 {
00289 pginfo = new ProgramInfo();
00290 pginfo->endts = QDateTime::currentDateTime().addSecs(-180);
00291 pginfo->pathname = QString::fromLocal8Bit(filename);
00292 pginfo->isVideo = true;
00293
00294
00295 if (filename.left(1) != "/" && !filename.startsWith("dvd:"))
00296 pginfo->pathname.prepend(QDir::currentDirPath() + '/');
00297 }
00298
00299 TV::StartTV(pginfo, false);
00300
00301 if (pginfo)
00302 delete pginfo;
00303
00304 if (priv_thread_created)
00305 {
00306 gContext->addPrivRequest(MythPrivRequest::MythExit, NULL);
00307 pthread_join(priv_thread, NULL);
00308 }
00309 delete gContext;
00310
00311 pa_ret = pulseaudio_handle_teardown();
00312 if (GENERIC_EXIT_OK != pa_ret)
00313 return pa_ret;
00314
00315 return TV_EXIT_OK;
00316 }
00317
00318