This repository was archived by the owner on Jun 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdlnaclient.cpp
220 lines (202 loc) · 9.52 KB
/
dlnaclient.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include "dlnaclient.h"
#include "dlnaexception.h"
#include "helpers.h"
#include <unistd.h>
DLNAClient::DLNAClient(QString data)
{
QStringList l = data.split("\r\n");
foreach(const QString &str, l)
{
if(str.contains("LOCATION:"))
{
QString e = str;
QStringList f = e.remove("LOCATION:").remove("http://").split(":");
ip = f[0];
StrPort = f[1].split("/")[0];
SMP = f[1].split("/")[1];
}
}
}
QString DLNAClient::GetPosition()
{//Returns the current position for the track that is playing on the DLNA server
QString XML = XMLHead + "<m:GetPositionInfo xmlns:m=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui4\">0</InstanceID></m:GetPositionInfo>" + XMLFoot + "\n";
QString Request = HelperDLNA::MakeRequest("POST", this->ControlURL, XML.length(), "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo", this->ip, this->StrPort) + XML;
return HelperDLNA::makeSocketGetReply(this->ip, this->StrPort, Request);
}
bool DLNAClient::isConnected()
{
this->connected = false;
QString request = HelperDLNA::MakeRequest("GET", this->SMP, 0, "", this->ip, this->StrPort);
QString response = HelperDLNA::makeSocketGetReply(this->ip, this->StrPort, request);
this->ReturnCode = HelperDLNA::GetResponseCode(response);
if(this->ReturnCode != 200) { return false;}
this->FriendlyName = HelperDLNA::getTag("friendlyname",HelperDLNA::removeHttpHeader(response));
for (QMap<QString, DLNAService>::iterator it = Services.begin(); it != Services.end(); ++it)
{
if(it.key().contains("avtransport"))
{
this->ControlURL = it.value().getControlURL();
this->connected = true;
return true;
}
}
return false;
}
QString DLNAClient::Desc()
{//Gets a description of the DLNA server
QString XML="<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:r=\"urn:schemas-rinconnetworks-com:metadata-1-0/\" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\">\n";
XML+="<item>\n";
XML+="<dc:title>Capital Edinburgh " + QString::number(QDateTime::currentDateTime().time().msec()); + "</dc:title>\n";
XML+="<upnp:class>object.item.audioItem.audioBroadcast</upnp:class>\n";
XML+="<desc id=\"cdudn\" nameSpace=\"urn:schemas-rinconnetworks-com:metadata-1-0/\">SA_RINCON65031_</desc>\n";
XML+="</item>\n";
XML += "</DIDL-Lite>\n";
return XML;
}
QString DLNAClient::TryToPlayFile(QString UrlToPlay)
{
if (!this->connected) this->connected = this->isConnected();//Someone might have turned the TV Off !
if (!this->connected) throw DLNAException("Error: Not Connected!");
for (QMap<QString, DLNAService>::iterator it = Services.begin(); it != Services.end(); ++it)
{
if(it.key().contains("avtransport"))
{//This is the service we are using so upload the file and then start playing
QString AddPlay = UploadFileToPlay(it.value().getControlURL(),UrlToPlay);
if (this->ReturnCode != 200) throw DLNAException("Cannot upload file");
QString PlayNow = StartPlay(it.value().getControlURL(),0);
if (this->ReturnCode == 200) return "OK"; else throw DLNAException("Error");
}
}
throw DLNAException("Couldnt find service");
}
QString DLNAClient::StartPlay(QString ControlURL, int Instance)
{//Start playing the new upload film or music track
QString XML = XMLHead;
XML += "<u:Play xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>"+ QString::number(Instance) + "</InstanceID><Speed>1</Speed></u:Play>\n";
XML += XMLFoot + "\n";
QString Request = HelperDLNA::MakeRequest("POST", this->ControlURL, XML.length(), "urn:schemas-upnp-org:service:AVTransport:1#Play", this->ip, this->StrPort) + XML;
return HelperDLNA::makeSocketGetReply(this->ip,this->StrPort,Request);
}
QString DLNAClient::StopPlay(bool ClearQueue)
{//If we are playing music tracks and not just a movie then clear our queue of tracks
if (!this->connected) this->connected = this->isConnected();//Someone might have turned the TV Off !
if (!this->connected) throw DLNAException("Error: Not Connected!");
if (ClearQueue)
{
this->PlayListQueue.clear();
this->PlayListPointer = 0;
}
return StopPlay(this->ControlURL , 0);
}
QString DLNAClient::StopPlay(QString ControlURL, int Instance)
{//Called to stop playing a movie or a music track
QString XML = XMLHead;
XML += "<u:Stop xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(Instance) + "</InstanceID></u:Stop>\n";
XML += XMLFoot + "\n";
QString Request = HelperDLNA::MakeRequest("POST", ControlURL, XML.length(), "urn:schemas-upnp-org:service:AVTransport:1#Stop", this->ip, this->StrPort) + XML;
return HelperDLNA::makeSocketGetReply(this->ip,this->StrPort,Request);
}
QString DLNAClient::UploadFileToPlay(QString ControlURL, QString UrlToPlay)
{///Later we will send a message to the DLNA server to start the file playing
QString XML = XMLHead;
XML += "<u:SetAVTransportURI xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">\n";
XML += "<InstanceID>0</InstanceID>\n";
XML += "<CurrentURI>" + UrlToPlay.replace(" ", "%20") + "</CurrentURI>\n";
XML += "<CurrentURIMetaData>" + Desc() + "</CurrentURIMetaData>\n";
XML += "</u:SetAVTransportURI>\n";
XML += XMLFoot + "\n";
QString Request = HelperDLNA::MakeRequest("POST", ControlURL, XML.length(), "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI", this->ip, this->StrPort) + XML;
return HelperDLNA::makeSocketGetReply(this->ip,this->StrPort,Request);
}
bool DLNAClient::AddToQueue(QString UrlToPlay, bool &NewTrackPlaying)
{//We add music tracks to a play list queue and then we poll the server so we know when to send the next track in the queue to play
if (!this->connected) this->connected = this->isConnected();//Someone might have turned the TV Off !
if (!this->connected) return false;
foreach (const QString &Url, PlayListQueue.values())
{
if (Url.toLower() == UrlToPlay.toLower())
return false;
}
PlayListQueue.insert(PlayListQueue.count() + 1, UrlToPlay);
if (!NewTrackPlaying)
{
PlayListPointer = PlayListQueue.count() + 1;
StopPlay(false);
TryToPlayFile(UrlToPlay);
NewTrackPlaying = true;
}
return false;
}
int DLNAClient::TotalSeconds(QString Value)
{//Convert the time left for the track to play back to seconds
QStringList val = Value.split(".");
if(!val.empty())
{
int Mins = val[1].split(':')[0].toInt();
int Secs = val[1].split(':')[1].toInt();
return Mins * 60 + Secs;
}
return 0;
}
int DLNAClient::PlayNextQueue(bool Force)
{//Play the next track in our queue but only if the current track is about to end or unless we are being forced
if (Force)
{//Looks like someone has pressed the next track button
PlayListPointer++;
if (PlayListQueue.count() == 0) return 0;
if (PlayListPointer > PlayListQueue.count())
PlayListPointer = 1;
QString Url = PlayListQueue[PlayListPointer];
StopPlay(false);
TryToPlayFile(Url);//Just play it
NoPlayCount = 0;
return 310;//Just guess for now how long the track is
}
else
{
QString HTMLPosition = GetPosition();
if (HTMLPosition.length() < 50) return 0;
QString TrackDuration = HelperDLNA::getTag("TrackDuration",HTMLPosition).toStdString().substr(2).c_str();
QString RelTime = HelperDLNA::getTag("RelTime",HTMLPosition).toStdString().substr(2).c_str();
int RTime = TotalSeconds(RelTime);
int TTime = TotalSeconds(TrackDuration);
if (RTime < 3 || TTime < 2)
{
NoPlayCount++;
if (NoPlayCount > 3)
{
StopPlay(false);
return PlayNextQueue(true);//Force the next track to start because the current track is about to end
}
else
return 0;
}
int SecondsToPlay = TTime - RTime - 5;
if (SecondsToPlay < 0) SecondsToPlay = 0;//Just a safeguard
if (SecondsToPlay <10)
{//Current track is about to end so wait a few seconds and then force the next track in our queue to play
usleep(((SecondsToPlay * 1000) +100)*1000);
return PlayNextQueue(true);
}
return SecondsToPlay;//Will have to wait to be polled again before playing the next track in our queue
}
}
QString DLNAClient::Pause(QString ControlURL, int Instance)
{//Called to pause playing a movie or a music track
QString XML = XMLHead;
XML += "<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>" + QString::number(Instance) + "</InstanceID></u:Pause>\n";
XML += XMLFoot + "\n";
QString Request = HelperDLNA::MakeRequest("POST", ControlURL, XML.length(), "urn:schemas-upnp-org:service:AVTransport:1#Pause", this->ip, this->StrPort) + XML;
return HelperDLNA::makeSocketGetReply(this->ip,this->StrPort,Request);
}
int DLNAClient::PlayPreviousQueue()
{//Play the previous track in our queue, we don't care if the current track has not completed or not, just do it
PlayListPointer--;
if (PlayListQueue.count() == 0) return 0;
if (PlayListPointer == 0)
PlayListPointer = PlayListQueue.count();
QString Url = PlayListQueue[PlayListPointer];
StopPlay(false);
TryToPlayFile(Url);
return 310;
}