angelclient.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include <QtNetwork>
  2. #include <QDesktopWidget>
  3. #include <QMessageBox>
  4. #include <QPainter>
  5. #include <QDebug>
  6. #include "angelclient.h"
  7. #include "ui_angelclient.h"
  8. #include "qtsvgbutton.h"
  9. const QString KXmlSource = "xmlsource";
  10. const QString KResponseStatus = "status";
  11. const QString KResponseText = "text";
  12. const QString KResponseType = "responsetype";
  13. const QString KRequest = "request";
  14. const QString KXqReadResponse = "let $root := doc($xmlsource)//response return data($root/%1)";
  15. const int KOneSecondInMs = 1000;
  16. // commands
  17. const QByteArray KPlay = "play";
  18. const QByteArray KPause = "pause";
  19. const QByteArray KNext = "next";
  20. const QByteArray KPrev = "prev";
  21. const QByteArray KNowPlaying = "nowplaying";
  22. const QByteArray KTrackDuration = "trackduration";
  23. const QByteArray KTrackPosition = "trackposition";
  24. const QByteArray KConnect = "connect";
  25. const QByteArray KSyncNow = "syncnow";
  26. #ifdef Q_OS_SYMBIAN
  27. #include <es_sock.h>
  28. #include <sys/socket.h>
  29. #include <net/if.h>
  30. static void setDefaultIapL()
  31. {
  32. RSocketServ serv;
  33. CleanupClosePushL(serv);
  34. User::LeaveIfError(serv.Connect());
  35. RConnection conn;
  36. CleanupClosePushL(conn);
  37. User::LeaveIfError(conn.Open(serv));
  38. User::LeaveIfError(conn.Start());
  39. _LIT(KIapNameSetting, "IAP\\Name");
  40. TBuf8<50> iap8Name;
  41. User::LeaveIfError(conn.GetDesSetting(TPtrC(KIapNameSetting), iap8Name));
  42. iap8Name.ZeroTerminate();
  43. conn.Stop();
  44. CleanupStack::PopAndDestroy(&conn);
  45. CleanupStack::PopAndDestroy(&serv);
  46. struct ifreq ifReq;
  47. memset(&ifReq, 0, sizeof(struct ifreq));
  48. strcpy( ifReq.ifr_name, (char*)iap8Name.Ptr());
  49. User::LeaveIfError(setdefaultif( &ifReq ));
  50. }
  51. static int setDefaultIap()
  52. {
  53. TRAPD(err, setDefaultIapL());
  54. qDebug()<<"Error in setDefaultIap: "<<err;
  55. return err;
  56. }
  57. #endif
  58. AngelClient::AngelClient(QWidget *parent) :
  59. QWidget(parent),
  60. ui(new Ui::AngelClient)
  61. {
  62. mCurrentRequest.clear();
  63. ui->setupUi(this);
  64. setFixedSize(sizeHint());
  65. setLayout(ui->masterLayout);
  66. ui->musicControlLayout->setSizeConstraint(QLayout::SetFixedSize);
  67. setButtonSize();
  68. ui->slider->setTracking(false);
  69. mXmlQuery = new QXmlQuery;
  70. mBuffer = new QBuffer(this);
  71. connect(ui->bindButton,SIGNAL(clicked()),this,SLOT(connectToServer()));
  72. mClientSocket = new QTcpSocket(this);
  73. connect(mClientSocket,SIGNAL(connected()),this,SLOT(handleHostFound()));
  74. connect(mClientSocket,SIGNAL(readyRead()),this,SLOT(readServerResponse()));
  75. connect(mClientSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(handleError(QAbstractSocket::SocketError)));
  76. // connect player controls
  77. connect(ui->playPauseButton,SIGNAL(clicked()),this,SLOT(playPause()));
  78. connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(next()));
  79. connect(ui->prevButton,SIGNAL(clicked()),this,SLOT(prev()));
  80. connect(ui->helpButton,SIGNAL(clicked()),this,SLOT(showHelp()));
  81. connect(ui->slider,SIGNAL(valueChanged(int)),this,SLOT(sliderValueChanged(int)));
  82. connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(sliderMoved(int)));
  83. #ifdef Q_OS_SYBIAN
  84. setDefaultIap();
  85. #endif
  86. ui->hostAddress->setText(hostAddressToConnect());
  87. ui->port->setText("1500");
  88. connectToServer();
  89. }
  90. AngelClient::~AngelClient()
  91. {
  92. delete ui;
  93. delete mXmlQuery;
  94. }
  95. QSize AngelClient::sizeHint()
  96. {
  97. QSize widgetSize(250,400);
  98. #ifdef Q_OS_SYMBIAN
  99. QDesktopWidget dw;
  100. widgetSize = dw.screenGeometry().size();
  101. #endif
  102. qDebug()<<"setting fixed size of "<<widgetSize;
  103. return widgetSize;
  104. }
  105. QString AngelClient::hostAddressToConnect()
  106. {
  107. QString ipAddress;
  108. QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
  109. qDebug()<<"ip list"<<ipAddressesList;
  110. // use the first non-localhost IPv4 address
  111. for (int i = 0; i < ipAddressesList.size(); ++i)
  112. {
  113. qDebug()<<"ipaddress:"<<ipAddressesList.at(i);
  114. if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
  115. ipAddressesList.at(i).toIPv4Address())
  116. {
  117. ipAddress = ipAddressesList.at(i).toString();
  118. qDebug()<<"host address to connect "<<ipAddress;
  119. return ipAddress;
  120. }
  121. }
  122. return QString();
  123. }
  124. void AngelClient::handleError(QAbstractSocket::SocketError error)
  125. {
  126. qDebug()<<__FUNCTION__;
  127. qDebug()<<"errornum:"<<error;
  128. ui->connectionStatus->setText(QString().setNum(error) + " " + mClientSocket->errorString());
  129. }
  130. void AngelClient::connectToServer()
  131. {
  132. qDebug()<<__FUNCTION__;
  133. mCurrentRequest = KConnect;
  134. QHostAddress hostAddress(ui->hostAddress->text());
  135. int port = ui->port->text().toInt();
  136. mClientSocket->abort();
  137. mClientSocket->connectToHost(hostAddress,port);
  138. }
  139. void AngelClient::handleHostFound()
  140. {
  141. qDebug()<<__FUNCTION__;
  142. ui->console->setText("connected to host");
  143. }
  144. void AngelClient::readServerResponse()
  145. {
  146. qDebug()<<__FUNCTION__;
  147. ui->console->clear();
  148. QDataStream in(mClientSocket);
  149. in.setVersion(QDataStream::Qt_4_0);
  150. in.device()->seek(0);
  151. QByteArray response = in.device()->readAll();
  152. int stat = readResponse(response,KResponseStatus).toInt();
  153. QString request = readResponse(response,KRequest).simplified();
  154. QString responseText = readResponse(response,KResponseText).simplified();
  155. if(200 != stat)
  156. {
  157. responseText = "Request failed!";
  158. }
  159. // This is a spl case, here we connect to server.
  160. else if(KConnect == mCurrentRequest)
  161. {
  162. ui->connectionStatus->setText(responseText);
  163. // Start playing after connection
  164. ui->playPauseButton->setText(KPlay);
  165. playPause();
  166. }
  167. else if(KSyncNow == responseText)
  168. {
  169. sync();
  170. }
  171. // TODO: Use a statemachine to handle it more elegantly
  172. else
  173. {
  174. if(KPlay == request ||
  175. KNext == request ||
  176. KPrev == request)
  177. {
  178. if(KPlay == request)
  179. {
  180. ui->playPauseButton->setEnabled(true);
  181. ui->playPauseButton->setText(KPause);
  182. }
  183. sendRequest(KNowPlaying);
  184. ui->playingStatus->setText("Playing");
  185. }
  186. else if(KPause == request)
  187. {
  188. ui->playPauseButton->setEnabled(true);
  189. ui->playPauseButton->setText(KPlay);
  190. ui->playingStatus->setText("Paused");
  191. }
  192. else if(KNowPlaying == request)
  193. {
  194. ui->title->setText(responseText);
  195. trackDuration();
  196. }
  197. else if(KTrackDuration == request)
  198. {
  199. mTrackDurationInSec = timeInSecs(responseText);
  200. ui->duration->setText(responseText);
  201. trackPosition();
  202. }
  203. else if(KTrackPosition == request)
  204. {
  205. int secs = timeInSecs(responseText);
  206. ui->slider->setRange(0,mTrackDurationInSec);
  207. ui->slider->setValue(secs);
  208. mTrackTimer.stop();
  209. mTrackTimer.start(KOneSecondInMs,this);
  210. mTrackElapsedTime.setHMS(0,0,secs,0);
  211. }
  212. }
  213. }
  214. QString AngelClient::readResponse(QString aSourceXml,QString aResponseType)
  215. {
  216. mBuffer->setData(aSourceXml.toUtf8());
  217. mBuffer->open(QIODevice::ReadOnly);
  218. mXmlQuery->bindVariable(KXmlSource,mBuffer);
  219. QString query = KXqReadResponse.arg(aResponseType);
  220. mXmlQuery->setQuery(query);
  221. QString result = QString();
  222. if(mXmlQuery->isValid())
  223. {
  224. mXmlQuery->evaluateTo(&result);
  225. }
  226. mBuffer->close();
  227. return result;
  228. }
  229. void AngelClient::playPause()
  230. {
  231. if(ui->playPauseButton->text() == KPlay)
  232. {
  233. sendRequest(KPlay);
  234. ui->playPauseButton->setEnabled(false);
  235. mIsPaused = false;
  236. }
  237. else if(ui->playPauseButton->text() == KPause)
  238. {
  239. sendRequest(KPause);
  240. ui->playPauseButton->setEnabled(false);
  241. mIsPaused = true;
  242. mTrackTimer.stop();
  243. }
  244. }
  245. void AngelClient::next()
  246. {
  247. sendRequest(KNext);
  248. }
  249. void AngelClient::prev()
  250. {
  251. sendRequest(KPrev);
  252. }
  253. void AngelClient::trackDuration()
  254. {
  255. sendRequest(KTrackDuration);
  256. }
  257. void AngelClient::trackPosition()
  258. {
  259. sendRequest(KTrackPosition);
  260. }
  261. void AngelClient::showHelp()
  262. {
  263. QMessageBox msg;
  264. msg.setText("Run Angel Server on your computer.\nIn case of connection error, manually set your IP address and port and then click connect.");
  265. msg.exec();
  266. }
  267. int AngelClient::timeInSecs(QString aTimeInText)
  268. {
  269. qDebug()<<aTimeInText;
  270. QString timeInText = aTimeInText.simplified();
  271. QStringList timeList = timeInText.split(":");
  272. qDebug()<<timeList<<timeList.count();
  273. mHasHourPart = false;
  274. if(2 >= timeList.count() && aTimeInText.contains(":")) // 2: time would be in the format hh:mm:ss
  275. {
  276. int hr = 0;
  277. int index = 0;
  278. mHasHourPart = false;
  279. if(3 == timeList.count()) // has hour part also
  280. {
  281. mHasHourPart = true;
  282. hr = timeList.at(index).toInt();
  283. ++index;
  284. }
  285. int min = timeList.at(index).toInt();
  286. index++;
  287. int sec = timeList.at(index).toInt();
  288. int result = (hr*60)*60 + min*60 + sec;
  289. return result;
  290. }
  291. return -1;
  292. }
  293. void AngelClient::paintEvent(QPaintEvent *aPaintEvent)
  294. {
  295. Q_UNUSED(aPaintEvent);
  296. QPixmap bg(":/resources/images/brushedmetal.jpg");
  297. QPainter painter(this);
  298. painter.setRenderHint(QPainter::SmoothPixmapTransform);
  299. painter.drawPixmap(rect(),bg);
  300. }
  301. void AngelClient::resizeEvent(QResizeEvent *aEvent)
  302. {
  303. setButtonSize();
  304. }
  305. void AngelClient::setButtonSize()
  306. {
  307. const QString KSkin("Beryl");
  308. #ifdef Q_OS_SYBIAN
  309. QSize buttonSize(150,150);
  310. #else
  311. QSize buttonSize(90,90);
  312. #endif
  313. ui->playPauseButton->resize(buttonSize);
  314. ui->playPauseButton->setSkin(KSkin);
  315. ui->nextButton->resize(buttonSize);
  316. ui->nextButton->setSkin(KSkin);
  317. ui->prevButton->resize(buttonSize);
  318. ui->prevButton->setSkin(KSkin);
  319. ui->playPauseButton->setText(KPause);
  320. }
  321. void AngelClient::timerEvent(QTimerEvent *aEvent)
  322. {
  323. if(!mIsPaused)
  324. {
  325. ui->slider->setValue(ui->slider->value()+1);
  326. }
  327. }
  328. void AngelClient::sliderValueChanged(int aNewValue)
  329. {
  330. if(!mIsPaused && aNewValue <= mTrackDurationInSec)
  331. {
  332. updateElapsedTime();
  333. }
  334. }
  335. void AngelClient::updateElapsedTime()
  336. {
  337. if(!mIsPaused)
  338. {
  339. mTrackElapsedTime = mTrackElapsedTime.addSecs(1);
  340. QString elapsedTimeText; // format time in hh:mm:ss
  341. elapsedTimeText = mTrackElapsedTime.toString("mm") + ":" +
  342. mTrackElapsedTime.toString("ss");
  343. if(mHasHourPart)
  344. {
  345. elapsedTimeText.insert(0,mTrackElapsedTime.toString("hh")+":");
  346. }
  347. ui->elapsed->setText(elapsedTimeText);
  348. }
  349. }
  350. void AngelClient::sliderMoved(int aNewValue)
  351. {
  352. Q_UNUSED(aNewValue);
  353. // For simplicity, disabling slider movement
  354. sync();
  355. }
  356. void AngelClient::sync()
  357. {
  358. mTrackTimer.stop();
  359. sendRequest(KNowPlaying);
  360. ui->console->setText("syncing...");
  361. }
  362. void AngelClient::sendRequest(QByteArray aRequest)
  363. {
  364. mCurrentRequest = aRequest;
  365. mClientSocket->write(aRequest);
  366. }
  367. // eof