--- a/src/cdplugins/tidal.cxx
+++ b/src/cdplugins/tidal.cxx
@@ -23,6 +23,7 @@
#include <vector>
#include <string.h>
#include <librtmp/rtmp.h>
+#include <upnp/upnp.h>
#include "cmdtalk.h"
@@ -110,7 +111,7 @@
if (mimetype.empty()) {
unordered_map<string, string> res;
if (!cmd.callproc("mimetype", {{"path", path}}, res)) {
- LOGERR("Tidal::get_media_url: slave failure\n");
+ LOGERR("Tidal::get_mimetype: slave failure\n");
return string();
}
@@ -134,6 +135,25 @@
return 0;
}
+class StreamHandle {
+public:
+ StreamHandle() : rtmp(nullptr), http_handle(nullptr) {
+ }
+ ~StreamHandle() {
+ if (rtmp) {
+ RTMP_Close(rtmp);
+ RTMP_Free(rtmp);
+ }
+ if (http_handle) {
+ UpnpCloseHttpGet(http_handle);
+ }
+ }
+
+ RTMP *rtmp;
+ void *http_handle;
+ int len;
+};
+
void *Tidal::Internal::open(const string& path)
{
LOGDEB("Tidal::open: " << path << endl);
@@ -141,50 +161,92 @@
if (media_url.empty()) {
return nullptr;
}
- RTMP *rtmp = RTMP_Alloc();
- RTMP_Init(rtmp);
-
- // Writable copy of url
- if (!RTMP_SetupURL(rtmp, strdup(media_url.c_str()))) {
- LOGERR("Tidal::open: RTMP_SetupURL failed for [" <<
- media_url << "]\n");
- RTMP_Free(rtmp);
- return nullptr;
- }
- if (!RTMP_Connect(rtmp, NULL)) {
- LOGERR("Tidal::open: RTMP_Connect failed for [" <<
- media_url << "]\n");
- RTMP_Free(rtmp);
- return nullptr;
- }
- if (!RTMP_ConnectStream(rtmp, 0)) {
- LOGERR("Tidal::open: RTMP_ConnectStream failed for [" <<
- media_url << "]\n");
- RTMP_Free(rtmp);
- return nullptr;
- }
-
- return rtmp;
-}
-
-int Tidal::Internal::read(void *hdl, char* buf, size_t cnt)
+ if (media_url.find("http") == 0) {
+ void *http_handle;
+ char *content_type;
+ int content_length;
+ int httpstatus;
+ int code = UpnpOpenHttpGet(media_url.c_str(), &http_handle,
+ &content_type, &content_length,
+ &httpstatus, 30);
+ LOGDEB("Tidal::open: UpnpOpenHttpGet: ret " << code <<
+ " mtype " << content_type << " length " << content_length <<
+ " HTTP status " << httpstatus << endl);
+ if (code) {
+ LOGERR("Tidal::open: UpnpOpenHttpGet: ret " << code <<
+ " mtype " << content_type << " length " << content_length <<
+ " HTTP status " << httpstatus << endl);
+ return nullptr;
+ }
+ StreamHandle *hdl = new StreamHandle;
+ hdl->http_handle = http_handle;
+ hdl->len = content_length;
+ return hdl;
+ } else {
+ RTMP *rtmp = RTMP_Alloc();
+ RTMP_Init(rtmp);
+
+ // Writable copy of url
+ if (!RTMP_SetupURL(rtmp, strdup(media_url.c_str()))) {
+ LOGERR("Tidal::open: RTMP_SetupURL failed for [" <<
+ media_url << "]\n");
+ RTMP_Free(rtmp);
+ return nullptr;
+ }
+ if (!RTMP_Connect(rtmp, NULL)) {
+ LOGERR("Tidal::open: RTMP_Connect failed for [" <<
+ media_url << "]\n");
+ RTMP_Free(rtmp);
+ return nullptr;
+ }
+ if (!RTMP_ConnectStream(rtmp, 0)) {
+ LOGERR("Tidal::open: RTMP_ConnectStream failed for [" <<
+ media_url << "]\n");
+ RTMP_Free(rtmp);
+ return nullptr;
+ }
+ StreamHandle *hdl = new StreamHandle;
+ hdl->rtmp = rtmp;
+ return hdl;
+ }
+}
+
+int Tidal::Internal::read(void *_hdl, char* buf, size_t cnt)
{
LOGDEB("Tidal::read: " << cnt << endl);
- if (!hdl)
- return -1;
- RTMP *rtmp = (RTMP *)hdl;
+ if (!_hdl)
+ return -1;
+
+ // The pupnp http code has a default 1MB buffer size which is much
+ // too big for us (too slow, esp. because tidal will stall).
if (cnt > 100 * 1024)
- cnt = 100 * 1024;
- size_t totread = 0;
- while (totread < cnt) {
- int didread = RTMP_Read(rtmp, buf+totread, cnt-totread);
- //LOGDEB("Tidal::read: RTMP_Read returned: " << didread << endl);
- if (didread <= 0)
- break;
- totread += didread;
- }
- LOGDEB("Tidal::read: total read: " << totread << endl);
- return totread > 0 ? totread : -1;
+ cnt = 100 * 1024;
+
+ StreamHandle *hdl = (StreamHandle *)_hdl;
+
+ if (hdl->rtmp) {
+ RTMP *rtmp = hdl->rtmp;
+ size_t totread = 0;
+ while (totread < cnt) {
+ int didread = RTMP_Read(rtmp, buf+totread, cnt-totread);
+ //LOGDEB("Tidal::read: RTMP_Read returned: " << didread << endl);
+ if (didread <= 0)
+ break;
+ totread += didread;
+ }
+ LOGDEB("Tidal::read: total read: " << totread << endl);
+ return totread > 0 ? totread : -1;
+ } else if (hdl->http_handle) {
+ int code = UpnpReadHttpGet(hdl->http_handle, buf, &cnt, 30);
+ if (code) {
+ LOGERR("Tidal::read: UpnpReadHttpGet returned " << code << endl);
+ return -1;
+ }
+ return int(cnt);
+ } else {
+ LOGERR("Tidal::read: neither rtmp nor http\n");
+ return -1;
+ }
}
off_t Tidal::Internal::seek(void *hdl, off_t offs, int whence)
@@ -193,14 +255,11 @@
return -1;
}
-void Tidal::Internal::close(void *hdl)
+void Tidal::Internal::close(void *_hdl)
{
LOGDEB("Tidal::close\n");
- if (hdl) {
- RTMP *rtmp = (RTMP *)hdl;
- RTMP_Close(rtmp);
- RTMP_Free(rtmp);
- }
+ StreamHandle *hdl = (StreamHandle *)_hdl;
+ delete hdl;
}