2
* Copyright (C) 2011 Tuomo Penttinen, all rights reserved.
4
* Author: Tuomo Penttinen <tp@herqq.org>
6
* This file is part of Herqq UPnP Av (HUPnPAv) library.
8
* Herqq UPnP Av is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
13
* Herqq UPnP Av is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with Herqq UPnP Av. If not, see <http://www.gnu.org/licenses/>.
22
#include "htransport_sinkservice_p.h"
23
#include "hmediarenderer_device_p.h"
24
#include "hmediarenderer_info.h"
25
#include "hrendererconnection_info.h"
26
#include "hrendererconnection.h"
28
#include "../transport/hmediainfo.h"
29
#include "../transport/hpositioninfo.h"
30
#include "../transport/htransportinfo.h"
31
#include "../transport/htransportaction.h"
32
#include "../transport/htransportsettings.h"
33
#include "../transport/hdevicecapabilities.h"
35
#include <HUpnpCore/private/hlogger_p.h>
37
#include <HUpnpCore/HUdn>
38
#include <HUpnpCore/HServiceId>
39
#include <HUpnpCore/HResourceType>
40
#include <HUpnpCore/HStateVariablesSetupData>
42
#include <QtCore/QSet>
43
#include <QtCore/QDir>
44
#include <QtCore/QFile>
45
#include <QtCore/QStringList>
46
#include <QtCore/QXmlStreamWriter>
57
/*******************************************************************************
58
* HTransportSinkService
59
******************************************************************************/
60
HTransportSinkService::HTransportSinkService() :
61
HAbstractTransportService(),
62
m_owner(0), m_lastId(-1)
66
HTransportSinkService::~HTransportSinkService()
70
bool HTransportSinkService::init(HMediaRendererDevice* owner)
77
qint32 HTransportSinkService::setAVTransportURI(
78
quint32 instanceId, const QUrl& currentUri,
79
const QString& currentUriMetaData)
81
if (currentUri.isEmpty() || !currentUri.isValid())
83
return UpnpInvalidArgs;
86
HRendererConnection* mediaConnection =
87
m_owner->findConnectionByAvTransportId(instanceId);
91
return HAvTransportInfo::InvalidInstanceId;
94
const HRendererConnectionInfo* info = mediaConnection->info();
95
if (info->mediaInfo().currentUri() == currentUri)
97
return HAvTransportInfo::ContentBusy;
100
if (currentUri.host().isEmpty())
102
QString localPath = currentUri.toLocalFile();
103
if (!QFile::exists(localPath) && !QDir(localPath).exists())
105
return HAvTransportInfo::ResourceNotFound;
110
return mediaConnection->setResource(currentUri, currentUriMetaData);
113
qint32 HTransportSinkService::setNextAVTransportURI(
114
quint32 instanceId, const QUrl& nextUri, const QString& nextUriMetaData)
116
if (nextUri.isEmpty() || !nextUri.isValid())
118
return UpnpInvalidArgs;
121
HRendererConnection* mediaConnection =
122
m_owner->findConnectionByAvTransportId(instanceId);
124
if (!mediaConnection)
126
return HAvTransportInfo::InvalidInstanceId;
129
const HRendererConnectionInfo* info = mediaConnection->info();
130
if (info->mediaInfo().currentUri() == nextUri)
132
return HAvTransportInfo::ContentBusy;
134
else if (info->mediaInfo().nextUri() == nextUri)
139
if (nextUri.host().isEmpty())
141
QString localPath = nextUri.toLocalFile();
142
if (!QFile::exists(localPath) && !QDir(localPath).exists())
144
return HAvTransportInfo::ResourceNotFound;
149
return mediaConnection->setNextResource(nextUri, nextUriMetaData);
152
qint32 HTransportSinkService::getMediaInfo(quint32 instanceId, HMediaInfo* retVal)
156
HRendererConnection* mediaConnection =
157
m_owner->findConnectionByAvTransportId(instanceId);
159
if (!mediaConnection)
161
return HAvTransportInfo::InvalidInstanceId;
164
*retVal = mediaConnection->info()->mediaInfo();
168
qint32 HTransportSinkService::getMediaInfo_ext(
169
quint32 instanceId, HMediaInfo* retVal)
171
return getMediaInfo(instanceId, retVal);
174
qint32 HTransportSinkService::getTransportInfo(
175
quint32 instanceId, HTransportInfo* retVal)
179
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
180
if (!mediaConnection)
182
return HAvTransportInfo::InvalidInstanceId;
185
*retVal = mediaConnection->info()->transportInfo();
189
qint32 HTransportSinkService::getPositionInfo(
190
quint32 instanceId, HPositionInfo* retVal)
194
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
195
if (!mediaConnection)
197
return HAvTransportInfo::InvalidInstanceId;
200
*retVal = mediaConnection->info()->positionInfo();
204
qint32 HTransportSinkService::getDeviceCapabilities(
205
quint32 instanceId, HDeviceCapabilities* retVal)
209
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
210
if (!mediaConnection)
212
return HAvTransportInfo::InvalidInstanceId;
215
*retVal = mediaConnection->info()->deviceCapabilities();
219
qint32 HTransportSinkService::stop(quint32 instanceId)
221
HRendererConnection* mediaConnection =
222
m_owner->findConnectionByAvTransportId(instanceId);
224
if (!mediaConnection)
226
return HAvTransportInfo::InvalidInstanceId;
229
return mediaConnection->stop();
232
qint32 HTransportSinkService::play(
233
quint32 instanceId, const QString& speed)
235
HRendererConnection* mediaConnection =
236
m_owner->findConnectionByAvTransportId(instanceId);
238
if (!mediaConnection)
240
return HAvTransportInfo::InvalidInstanceId;
243
return mediaConnection->play(speed);
246
qint32 HTransportSinkService::pause(quint32 instanceId)
248
HRendererConnection* mediaConnection =
249
m_owner->findConnectionByAvTransportId(instanceId);
251
if (!mediaConnection)
253
return HAvTransportInfo::InvalidInstanceId;
256
return mediaConnection->pause();
259
qint32 HTransportSinkService::record(quint32 instanceId)
261
HRendererConnection* mediaConnection =
262
m_owner->findConnectionByAvTransportId(instanceId);
264
if (!mediaConnection)
266
return HAvTransportInfo::InvalidInstanceId;
269
return mediaConnection->record();
272
qint32 HTransportSinkService::seek(quint32 instanceId, const HSeekInfo& seekInfo)
274
HRendererConnection* mediaConnection =
275
m_owner->findConnectionByAvTransportId(instanceId);
277
if (!mediaConnection)
279
return HAvTransportInfo::InvalidInstanceId;
282
return mediaConnection->seek(seekInfo);
285
qint32 HTransportSinkService::next(quint32 instanceId)
287
HRendererConnection* mediaConnection =
288
m_owner->findConnectionByAvTransportId(instanceId);
290
if (!mediaConnection)
292
return HAvTransportInfo::InvalidInstanceId;
295
return mediaConnection->next();
298
qint32 HTransportSinkService::previous(quint32 instanceId)
300
HRendererConnection* mediaConnection =
301
m_owner->findConnectionByAvTransportId(instanceId);
303
if (!mediaConnection)
305
return HAvTransportInfo::InvalidInstanceId;
308
return mediaConnection->previous();
311
qint32 HTransportSinkService::setPlayMode(
312
quint32 instanceId, const HPlayMode& playMode)
314
HRendererConnection* mediaConnection =
315
m_owner->findConnectionByAvTransportId(instanceId);
317
if (!mediaConnection)
319
return HAvTransportInfo::InvalidInstanceId;
322
return mediaConnection->setPlaymode(playMode);
325
qint32 HTransportSinkService::setRecordQualityMode(
326
quint32 instanceId, const HRecordQualityMode& rqMode)
328
HRendererConnection* mediaConnection =
329
m_owner->findConnectionByAvTransportId(instanceId);
331
if (!mediaConnection)
333
return HAvTransportInfo::InvalidInstanceId;
336
return mediaConnection->setRecordQualityMode(rqMode);
339
qint32 HTransportSinkService::getTransportSettings(
340
quint32 instanceId, HTransportSettings* retVal)
344
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
345
if (!mediaConnection)
347
return HAvTransportInfo::InvalidInstanceId;
350
*retVal = mediaConnection->info()->transportSettings();
354
qint32 HTransportSinkService::getCurrentTransportActions(
355
quint32 instanceId, QSet<HTransportAction>* retVal)
359
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
360
if (!mediaConnection)
362
return HAvTransportInfo::InvalidInstanceId;
365
*retVal = mediaConnection->info()->currentTransportActions();
369
qint32 HTransportSinkService::getDrmState(
370
quint32 instanceId, HAvTransportInfo::DrmState* retVal)
374
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
375
if (!mediaConnection)
377
return HAvTransportInfo::InvalidInstanceId;
380
*retVal = mediaConnection->info()->drmState();
386
//void addNamespaces(QXmlStreamReader& reader)
388
// QXmlStreamNamespaceDeclaration def(
389
// "", "urn:schemas-upnp-org:av:avs");
390
// QXmlStreamNamespaceDeclaration xsi(
391
// "xsi", "http://www.w3.org/2001/XMLSchema-instance");
392
// QXmlStreamNamespaceDeclaration xsiSchemaLocation(
393
// "xsi:schemaLocation", "urn:schemas-upnp-org:av:avs\r\nhttp://www.upnp.org/schemas/av/avs.xsd");
395
// reader.addExtraNamespaceDeclaration(def);
396
// reader.addExtraNamespaceDeclaration(xsi);
397
// reader.addExtraNamespaceDeclaration(xsiSchemaLocation);
401
qint32 HTransportSinkService::getStateVariables(
402
quint32 instanceId, const QSet<QString>& stateVariableNames,
403
QString* stateVariableValuePairs)
405
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
407
Q_ASSERT(stateVariableValuePairs);
409
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
410
if (!mediaConnection)
412
return HAvTransportInfo::InvalidInstanceId;
416
QXmlStreamWriter writer(&retVal);
418
writer.setCodec("UTF-8");
419
writer.writeStartDocument();
420
writer.writeStartElement("stateVariableValuePairs");
421
writer.writeDefaultNamespace("urn:schemas-upnp-org:av:avs");
422
writer.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
423
writer.writeAttribute("xsi:schemaLocation",
424
"urn:schemas-upnp-org:av:avs " \
425
"http://www.upnp.org/schemas/av/avs.xsd");
427
QSet<QString> stateVarNames;
428
if (stateVariableNames.contains("*"))
430
stateVarNames = HAvTransportInfo::stateVariablesSetupData().names();
431
QSet<QString>::iterator it = stateVarNames.begin();
432
for(; it != stateVarNames.end();)
434
if (it->startsWith("A_ARG") || *it == "LastChange")
436
it = stateVarNames.erase(it);
446
stateVarNames = stateVariableNames;
449
foreach(QString svName, stateVarNames)
451
svName = svName.trimmed();
452
if (svName.compare("LastChange", Qt::CaseInsensitive) == 0 ||
453
svName.startsWith("A_ARG", Qt::CaseInsensitive))
455
return HAvTransportInfo::InvalidStateVariableList;
459
QString value = mediaConnection->info()->value(svName, &ok);
462
writer.writeStartElement("stateVariable");
463
writer.writeAttribute("variableName", svName);
464
writer.writeCharacters(value);
465
writer.writeEndElement();
469
HLOG_WARN(QString("Could not get the value of state variable [%1]").arg(svName));
470
return HAvTransportInfo::InvalidStateVariableList;
473
writer.writeEndElement();
475
*stateVariableValuePairs = retVal;
479
qint32 HTransportSinkService::setStateVariables(
480
quint32 instanceId, const HUdn& avtUdn,
481
const HResourceType& serviceType, const HServiceId& serviceId,
482
const QString& stateVariableValuePairs, QStringList* stateVariableList)
484
HLOG2(H_AT, H_FUN, h_ptr->m_loggingIdentifier);
486
Q_ASSERT(stateVariableList);
488
HRendererConnection* mediaConnection = m_owner->findConnectionByAvTransportId(instanceId);
489
if (!mediaConnection)
491
return HAvTransportInfo::InvalidInstanceId;
494
if (avtUdn.isValid(LooseChecks) && avtUdn != parentDevice()->info().udn())
496
HLOG_WARN(QString("setStateVariables() invoked with invalid UDN [%1]").arg(avtUdn.toString()));
497
return UpnpInvalidArgs;
499
else if (serviceType.isValid() &&
500
!HAvTransportInfo::supportedServiceType().compare(serviceType, HResourceType::Inclusive))
502
return HAvTransportInfo::InvalidServiceType;
504
else if (serviceId.isValid(LooseChecks) &&
505
serviceId != HMediaRendererInfo::defaultAvTransportId())
507
return HAvTransportInfo::InvalidServiceId;
510
QXmlStreamReader reader(stateVariableValuePairs.trimmed());
511
//addNamespaces(reader);
513
if (reader.readNextStartElement())
515
if (reader.name().compare("stateVariableValuePairs", Qt::CaseInsensitive) != 0)
517
return UpnpInvalidArgs;
522
if (reader.error() != QXmlStreamReader::NoError)
524
HLOG_WARN(QString("XML parse failed: %1").arg(reader.errorString()));
526
return UpnpInvalidArgs;
529
stateVariableList->clear();
530
while(!reader.atEnd() && reader.readNextStartElement())
532
QStringRef name = reader.name();
533
if (name == "stateVariable")
535
QXmlStreamAttributes attrs = reader.attributes();
536
if (!attrs.hasAttribute(QString("variableName")))
538
HLOG_WARN(QString("Ignoring state variable value pair definition that lacks the [variableName] attribute."));
542
QString svName = attrs.value("variableName").toString();
543
QString value = reader.readElementText().trimmed();
545
if (mediaConnection->setValue(svName, value))
547
stateVariableList->append(svName);
551
HLOG_WARN(QString("Could not set the value of state variable [%1]").arg(svName));
552
stateVariableList->removeDuplicates();
553
return HAvTransportInfo::InvalidStateVariableValue;
559
HLOG_WARN(QString("Encountered unknown XML element: [%1]").arg(name.toString()));
563
stateVariableList->removeDuplicates();
567
qint32 HTransportSinkService::nextId()