TTKMusicPlayer  4.1.3.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
qdlnaclient.cpp
Go to the documentation of this file.
1 #include "qdlnaclient.h"
2 #include "qdlnaxml.h"
3 
4 #include <QMap>
5 #include <unistd.h>
6 #include <QFileInfo>
7 #include <QStringList>
8 
9 static constexpr const char *AVTRANSPORT = "avtransport";
10 
11 static const QString XML_HEAD = "<?xml version=\"1.0\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n<SOAP-ENV:Body>\n";
12 static const QString XML_FOOT = "</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n";
13 static const QString META_DATA = "&lt;DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\""
14  " xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\""
15  " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
16  " xmlns:sec=\"http://www.sec.co.kr/\"&gt;&lt;item id=\"f-0\" parentID=\"0\" restricted=\"0\"&gt;"
17  "&lt;dc:title&gt;%1&lt;/dc:title&gt;"
18  "&lt;dc:creator&gt;%2&lt;/dc:creator&gt;"
19  "&lt;upnp:class&gt;object.item.%3Item&lt;/upnp:class&gt;"
20  "&lt;res protocolInfo=\"http-get:*:%4:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000\" &gt;"
21  "%5&lt;/res&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;";
22 static const QStringList AVT_NAMES = {"avtransport", "AVTransport"};
23 static const QStringList FRIENS_NAMES = {"friendlyname", "friendlyName", "FriendlyName", "FriendlyName"};
24 
28 class QDlnaClientPrivate : public TTKPrivate<QDlnaClient>
29 {
30 public:
32 
33  void initialize(const QString &data);
34  bool connect();
35 
37 
39  QString m_smp, m_controlURL;
40  QString m_friendlyName;
41  QMap<QString, QDlnaService> m_services;
42 
43 };
44 
46  : m_isConnected(false)
47 {
48 
49 }
50 
51 void QDlnaClientPrivate::initialize(const QString &data)
52 {
53  const QStringList &list = data.split(TTK_WLINEFEED);
54  for(QString str : qAsConst(list))
55  {
56  QStringList data_list;
57  if(str.contains("LOCATION:"))
58  {
59  data_list = str.remove("LOCATION: http://").split(":");
60  }
61  else if(str.contains("Location:"))
62  {
63  data_list = str.remove("Location: http://").split(":");
64  }
65  else if(str.contains("location:"))
66  {
67  data_list = str.remove("location: http://").split(":");
68  }
69 
70  if(data_list.count() >= 2)
71  {
72  m_serverIP = data_list[0];
73  const QStringList &info_list = data_list[1].split(TTK_SEPARATOR);
74 
75  if(info_list.count() >= 2)
76  {
77  m_serverPort = info_list[0];
78  m_smp = info_list[1];
79  }
80  }
81  }
82 }
83 
85 {
86  const QString &request = QDlna::makeRequest("GET", m_smp, 0, {}, m_serverIP, m_serverPort);
87  const QString &response = QDlna::makeSocketGetReply(m_serverIP, m_serverPort, request);
88  TTK_INFO_STREAM(m_serverIP << m_serverPort << m_smp << response);
89  if(!QDlna::isValid(response))
90  {
91  return false;
92  }
93 
94  QDlnaXml xml;
95  if(!xml.fromString(xml.tagNameToLower(QDlna::removeHttpHeader(response))))
96  {
97  return false;
98  }
99  //
100  for(const QString &name : qAsConst(FRIENS_NAMES))
101  {
103  if(!m_friendlyName.isEmpty())
104  {
105  break;
106  }
107  }
108  if(m_friendlyName.isEmpty())
109  {
110  return false;
111  }
112  //
113  for(const QString &name : qAsConst(AVT_NAMES))
114  {
115  const QDlnaService &server = xml.readServiceTag(name, "server");
116  if(!server.isEmpty())
117  {
118  m_services.insert(AVTRANSPORT, server);
119  break;
120  }
121  }
122  //
123  for(const QString &name : qAsConst(AVT_NAMES))
124  {
125  const QDlnaService &server = xml.readServiceTag(name, "service");
126  if(!server.isEmpty())
127  {
128  m_services.insert(AVTRANSPORT, server);
129  break;
130  }
131  }
132  //
133  for(auto it = m_services.begin(); it != m_services.end(); ++it)
134  {
135  if(it.key().contains(AVTRANSPORT))
136  {
137  m_controlURL = it.value().m_controlURL;
138  m_isConnected = true;
139  return true;
140  }
141  }
142  return false;
143 }
144 
145 
146 
147 QDlnaClient::QDlnaClient(const QString &data)
148 {
151  d->initialize(data);
152 }
153 
154 QString QDlnaClient::server() const
155 {
157  return d->m_serverIP;
158 }
159 
160 QString QDlnaClient::serverName() const
161 {
163  return d->m_friendlyName;
164 }
165 
167 {
169  return d->connect();
170 }
171 
173 {
175  return d->m_isConnected;
176 }
177 
178 bool QDlnaClient::open(const QString &url) const
179 {
181  //Later we will send a message to the DLNA server to start the file playing
182  QFileInfo fin(url);
183  QString play_url = url;
184  QString body = XML_HEAD;
185  play_url.replace(TTK_SPACE, "%20");
186 
187  body += "<u:SetAVTransportURI xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">\n";
188  body += "<InstanceID>0</InstanceID>\n";
189  body += "<CurrentURI>" + play_url + "</CurrentURI>\n";
190  body += "<CurrentURIMetaData>" + META_DATA.arg(fin.baseName(), fin.owner(), "audio", "audio/mp3", play_url) + "</CurrentURIMetaData>\n";
191  body += "</u:SetAVTransportURI>\n";
192  body += XML_FOOT + "\n";
193  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI", d->m_serverIP,d->m_serverPort) + body;
194  TTK_INFO_STREAM(request);
195  return QDlna::isValid(QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request));
196 }
197 
198 bool QDlnaClient::play(int instance) const
199 {
201  //Start playing the new upload film or music track
202  QString body = XML_HEAD;
203  body += "<u:Play xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>"+ QString::number(instance) + "</InstanceID><Speed>1</Speed></u:Play>\n";
204  body += XML_FOOT + "\n";
205  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#Play", d->m_serverIP, d->m_serverPort) + body;
206  return QDlna::isValid(QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request));
207 }
208 
209 bool QDlnaClient::pause(int instance) const
210 {
212  //Called to pause playing a movie or a music track
213  QString body = XML_HEAD;
214  body += "<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(instance) + "</InstanceID></u:Pause>\n";
215  body += XML_FOOT + "\n";
216  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#Pause", d->m_serverIP, d->m_serverPort) + body;
217  return QDlna::isValid(QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request));
218 }
219 
220 bool QDlnaClient::stop(int instance) const
221 {
223  //Called to stop playing a movie or a music track
224  QString body = XML_HEAD;
225  body += "<u:Stop xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(instance) + "</InstanceID></u:Stop>\n";
226  body += XML_FOOT + "\n";
227  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#Stop", d->m_serverIP, d->m_serverPort) + body;
228  return QDlna::isValid(QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request));
229 }
230 
231 bool QDlnaClient::remove(int instance) const
232 {
234  //Called to remove queue track
235  QString body = XML_HEAD;
236  body += "<u:RemoveAllTracksFromQueue xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(instance) + "</InstanceID></u:RemoveAllTracksFromQueue>\n";
237  body += XML_FOOT + "\n";
238  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#RemoveAllTracksFromQueue", d->m_serverIP, d->m_serverPort) + body;
239  return QDlna::isValid(QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request));
240 }
241 
242 static qint64 valueToSecond(const QString &value)
243 {
244  return QDateTime::fromString(value, TTK_TIMES_FORMAT).toMSecsSinceEpoch() / 1000;
245 }
246 
247 bool QDlnaClient::position(qint64 &position, qint64 &duration, int instance) const
248 {
250  //Returns the current position for the track that is playing on the DLNA server
251  QString body = XML_HEAD;
252  body += "<u:GetPositionInfo xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(instance) + "</InstanceID></u:GetPositionInfo>\n";
253  body += XML_FOOT + "\n";
254  const QString &request = QDlna::makeRequest("POST", d->m_controlURL, body.length(), "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo", d->m_serverIP, d->m_serverPort) + body;
255  const QString &response = QDlna::makeSocketGetReply(d->m_serverIP, d->m_serverPort, request);
256  if(!QDlna::isValid(response))
257  {
258  return false;
259  }
260 
261  QDlnaXml xml;
262  if(!xml.fromString(QDlna::removeHttpHeader(response)))
263  {
264  return false;
265  }
266 
267  position = valueToSecond(xml.readTagNameValue("Relime"));
268  duration = valueToSecond(xml.readTagNameValue("TrackDuration"));
269  return true;
270 }
bool isValid(const QString &data)
Definition: qdlna.cpp:76
bool remove(int instance=0) const
#define TTK_TIMES_FORMAT
Definition: ttkglobal.h:229
QMap< QString, QDlnaService > m_services
Definition: qdlnaclient.cpp:41
bool pause(int instance=0) const
QString makeRequest(const QString &methord, const QString &url, int length, const QString &soapAction, const QString &ip, const QString &port)
Definition: qdlna.cpp:39
QString removeHttpHeader(const QString &data)
Definition: qdlna.cpp:70
The class of the dlna client.
Definition: qdlnaclient.h:29
static const QStringList AVT_NAMES
Definition: qdlnaclient.cpp:22
QString tagNameToLower(const QString &data) const
Definition: qdlnaxml.cpp:56
The class of the dlna xml.
Definition: qdlnaxml.h:29
QString readTagNameValue(const QString &tagName) const
Definition: qdlnaxml.cpp:75
QString makeSocketGetReply(const QString &ip, const QString &port, const QString &data)
Definition: qdlna.cpp:9
bool isEmpty() const
Definition: qdlnaservice.h:35
#define qAsConst
Definition: ttkqtglobal.h:51
const char * name
Definition: http_parser.c:458
bool play(int instance=0) const
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:68
bool connect() const
static const QString XML_FOOT
Definition: qdlnaclient.cpp:12
#define TTK_SEPARATOR
Definition: ttkglobal.h:196
static qint64 valueToSecond(const QString &value)
bool position(qint64 &position, qint64 &duration, int instance=0) const
The class of the dlna service.
Definition: qdlnaservice.h:27
static const QStringList FRIENS_NAMES
Definition: qdlnaclient.cpp:23
void initialize(const QString &data)
Definition: qdlnaclient.cpp:51
The class of the dlna client private.
Definition: qdlnaclient.cpp:28
static const QString XML_HEAD
Definition: qdlnaclient.cpp:11
static const QString META_DATA
Definition: qdlnaclient.cpp:13
bool open(const QString &url) const
#define TTK_WLINEFEED
Definition: ttkglobal.h:199
QDlnaService readServiceTag(const QString &type, const QString &tagName) const
Definition: qdlnaxml.cpp:82
QString server() const
bool stop(int instance=0) const
#define TTK_INIT_PRIVATE(Class)
Definition: ttkprivate.h:33
The class of the ttk private base.
Definition: ttkprivate.h:48
static constexpr const char * AVTRANSPORT
Definition: qdlnaclient.cpp:9
QDlnaClient(const QString &data)
bool isConnected() const
QString serverName() const
#define TTK_SPACE
Definition: ttkglobal.h:195
bool fromString(const QString &data)
Definition: qdlnaxml.cpp:36
#define TTK_D(Class)
Definition: ttkprivate.h:41