00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <cstdio>
00029 #include <cstdlib>
00030 #include <cstring>
00031 #include <unistd.h>
00032 #include <pthread.h>
00033 #include <sys/types.h>
00034
00035 #include <qapplication.h>
00036 #include <qsocketdevice.h>
00037 #include <qsocketnotifier.h>
00038 #include <qhostaddress.h>
00039
00040 #include "udpnotify.h"
00041 #include "mythcontext.h"
00042 #include "osd.h"
00043 #include "tv_play.h"
00044 #include "compat.h"
00045
00046 UDPNotifyOSDSet::UDPNotifyOSDSet(const QString &name)
00047 {
00048 m_name = name;
00049
00050 allTypes = new vector<UDPNotifyOSDTypeText *>;
00051 }
00052
00053 UDPNotifyOSDSet::~UDPNotifyOSDSet()
00054 {
00055 vector<UDPNotifyOSDTypeText *>::iterator i = allTypes->begin();
00056 for (; i != allTypes->end(); i++)
00057 {
00058 UDPNotifyOSDTypeText *type = (*i);
00059 if (type)
00060 delete type;
00061 }
00062 delete allTypes;
00063 }
00064
00065 UDPNotifyOSDTypeText *UDPNotifyOSDSet::GetType(const QString &name)
00066 {
00067 UDPNotifyOSDTypeText *ret = NULL;
00068 if (typesMap.contains(name))
00069 ret = typesMap[name];
00070
00071 return ret;
00072 }
00073
00074 void UDPNotifyOSDSet::ResetTypes(void)
00075 {
00076 typesMap.clear();
00077 allTypes->clear();
00078 }
00079
00080 void UDPNotifyOSDSet::AddType(UDPNotifyOSDTypeText *type, QString name)
00081 {
00082 typesMap[name] = type;
00083 allTypes->push_back(type);
00084 }
00085
00086 QString UDPNotifyOSDSet::GetName(void)
00087 {
00088 return m_name;
00089 }
00090
00091 vector<UDPNotifyOSDTypeText *> *UDPNotifyOSDSet::GetTypeList()
00092 {
00093 return allTypes;
00094 }
00095
00096 UDPNotifyOSDTypeText::UDPNotifyOSDTypeText(const QString &name,
00097 const QString &text)
00098 {
00099 m_name = name;
00100 m_text = text;
00101 }
00102
00103 UDPNotifyOSDTypeText::~UDPNotifyOSDTypeText()
00104 {
00105 }
00106
00107 QString UDPNotifyOSDTypeText::GetName(void)
00108 {
00109 return m_name;
00110 }
00111
00112 QString UDPNotifyOSDTypeText::GetText(void)
00113 {
00114 return m_text;
00115 }
00116
00117 void UDPNotifyOSDTypeText::SetText(const QString &text)
00118 {
00119 m_text = text;
00120 }
00121
00122 UDPNotify::UDPNotify(TV *tv, int udp_port)
00123 : QObject()
00124 {
00125 m_tv = tv;
00126 setList = new vector<UDPNotifyOSDSet *>;
00127
00128
00129 bcastaddr.setAddress("0.0.0.0");
00130
00131
00132 m_udp_port = udp_port;
00133
00134
00135 qApp->lock();
00136
00137 qsd = new QSocketDevice(QSocketDevice::Datagram);
00138 if (!qsd->bind(bcastaddr, udp_port))
00139 {
00140 VERBOSE(VB_IMPORTANT, QString("Could not bind to UDP notify port: %1")
00141 .arg(udp_port));
00142 qsn = NULL;
00143 }
00144 else
00145 {
00146
00147 qsn = new QSocketNotifier(qsd->socket(), QSocketNotifier::Read);
00148
00149
00150 connect(qsn, SIGNAL(activated(int)), this, SLOT(incomingData(int)));
00151 }
00152
00153 qApp->unlock();
00154 }
00155
00156 UDPNotify::~UDPNotify(void)
00157 {
00158 qApp->lock();
00159
00160 if (qsn != NULL)
00161 disconnect(qsn, SIGNAL(activated(int)), this, SLOT(incomingData(int)));
00162
00163 qsd->close();
00164
00165 delete qsd;
00166
00167 if (qsn)
00168 delete qsn;
00169
00170 qApp->unlock();
00171
00172 vector<UDPNotifyOSDSet *>::iterator i = setList->begin();
00173 for (; i != setList->end(); i++)
00174 {
00175 UDPNotifyOSDSet *set = (*i);
00176 if (set)
00177 delete set;
00178 }
00179 delete setList;
00180 }
00181
00182 void UDPNotify::AddSet(UDPNotifyOSDSet *set, QString name)
00183 {
00184 setMap[name] = set;
00185 setList->push_back(set);
00186 }
00187
00188 UDPNotifyOSDSet *UDPNotify::GetSet(const QString &text)
00189 {
00190 UDPNotifyOSDSet *ret = NULL;
00191 if (setMap.contains(text))
00192 ret = setMap[text];
00193
00194 return ret;
00195 }
00196
00197 QString UDPNotify::getFirstText(QDomElement &element)
00198 {
00199 for (QDomNode dname = element.firstChild(); !dname.isNull();
00200 dname = dname.nextSibling())
00201 {
00202 QDomText t = dname.toText();
00203 if (!t.isNull())
00204 return t.data();
00205 }
00206 return "";
00207 }
00208
00209 void UDPNotify::parseTextArea(UDPNotifyOSDSet *container, QDomElement &element)
00210 {
00211 QString value;
00212 QString name = element.attribute("name", "");
00213 if (name.isNull() || name.isEmpty())
00214 {
00215 VERBOSE(VB_IMPORTANT, "Text area needs a name");
00216 return;
00217 }
00218
00219 for (QDomNode child = element.firstChild(); !child.isNull();
00220 child = child.nextSibling())
00221 {
00222 QDomElement info = child.toElement();
00223 if (!info.isNull())
00224 {
00225 if (info.tagName() == "value")
00226 {
00227 value = getFirstText(info);
00228
00229 UDPNotifyOSDTypeText *text = container->GetType(name);
00230 if (text != NULL)
00231 {
00232 text->SetText(value);
00233 }
00234 else
00235 {
00236 text = new UDPNotifyOSDTypeText(name, value);
00237 container->AddType(text, name);
00238 }
00239 }
00240 else
00241 {
00242 VERBOSE(VB_IMPORTANT, QString("Unknown tag in text area: %1")
00243 .arg(info.tagName()));
00244 }
00245 }
00246 }
00247 }
00248
00249 UDPNotifyOSDSet *UDPNotify::parseContainer(QDomElement &element)
00250 {
00251 QString name = element.attribute("name", "");
00252 if (name.isNull() || name.isEmpty())
00253 {
00254 VERBOSE(VB_IMPORTANT, "Container needs a name");
00255 return NULL;
00256 }
00257
00258 UDPNotifyOSDSet *container = GetSet(name);
00259
00260 if (container != NULL)
00261 {
00262 ClearContainer(container);
00263 }
00264 else
00265 {
00266 container = new UDPNotifyOSDSet(name);
00267 AddSet(container, name);
00268 }
00269
00270 for (QDomNode child = element.firstChild(); !child.isNull();
00271 child = child.nextSibling())
00272 {
00273 QDomElement info = child.toElement();
00274 if (!info.isNull())
00275 {
00276 if (info.tagName() == "textarea")
00277 {
00278 parseTextArea(container, info);
00279 }
00280 else
00281 {
00282 VERBOSE(VB_IMPORTANT, QString("Unknown container child: %1")
00283 .arg(info.tagName()));
00284 }
00285 }
00286 }
00287
00288 return container;
00289 }
00290
00291 void UDPNotify::ClearContainer(UDPNotifyOSDSet *container)
00292 {
00293 OSD *osd = m_tv->GetOSD();
00294
00295 if (osd)
00296 osd->ClearNotify(container);
00297 container->ResetTypes();
00298 }
00299
00300 void UDPNotify::incomingData(int socket)
00301 {
00302 OSD *osd = m_tv->GetOSD();
00303 QByteArray buf;
00304 int nr;
00305
00306 socket = socket;
00307
00308
00309 buf.resize(qsd->bytesAvailable());
00310 nr = qsd->readBlock(buf.data(), qsd->bytesAvailable());
00311 if (nr < 0)
00312 {
00313 VERBOSE(VB_IMPORTANT, "Error reading from udpnotify socket");
00314 return;
00315 }
00316 buf.resize(nr);
00317
00318
00319
00320
00321
00322 QString errorMsg;
00323 int errorLine = 0;
00324 int errorColumn = 0;
00325
00326 if (!doc.setContent(buf, false, &errorMsg, &errorLine, &errorColumn))
00327 {
00328 VERBOSE(VB_IMPORTANT, QString("Error parsing udpnotify xml:\n"
00329 "at line: %1 column: %2\n%3")
00330 .arg(errorLine)
00331 .arg(errorColumn)
00332 .arg(errorMsg));
00333 return;
00334 }
00335
00336 int displaytime = gContext->GetNumSetting("OSDNotifyTimeout", 5);
00337
00338 QDomElement docElem = doc.documentElement();
00339 if (!docElem.isNull())
00340 {
00341 if (docElem.tagName() != "mythnotify")
00342 {
00343 VERBOSE(VB_IMPORTANT, "Unknown UDP packet (not <mythnotify> XML)");
00344 return;
00345 }
00346
00347 QString version = docElem.attribute("version", "");
00348 if (version.isNull() || version.isEmpty())
00349 {
00350 VERBOSE(VB_IMPORTANT, "<mythnotify> missing 'version' attribute");
00351 return;
00352 }
00353
00354 QString disptime = docElem.attribute("displaytime", "");
00355 if (!disptime.isNull() && !disptime.isEmpty())
00356 displaytime = disptime.toInt();
00357 }
00358
00359 QDomNode n = docElem.firstChild();
00360 while (!n.isNull())
00361 {
00362 QDomElement e = n.toElement();
00363 if (!e.isNull())
00364 {
00365 if (e.tagName() == "container")
00366 {
00367 UDPNotifyOSDSet *container = parseContainer(e);
00368 if (osd && container)
00369 osd->StartNotify(container, displaytime);
00370 }
00371 else
00372 {
00373 VERBOSE(VB_IMPORTANT, QString("Unknown element: %1")
00374 .arg(e.tagName()));
00375 return;
00376 }
00377 }
00378 n = n.nextSibling();
00379 }
00380 }
00381