1617b62c9SDario Casalinuovo /* 2617b62c9SDario Casalinuovo * Copyright 2016, Dario Casalinuovo 3617b62c9SDario Casalinuovo * Distributed under the terms of the MIT License. 4617b62c9SDario Casalinuovo */ 5617b62c9SDario Casalinuovo 6617b62c9SDario Casalinuovo 7617b62c9SDario Casalinuovo #include "HTTPMediaIO.h" 8617b62c9SDario Casalinuovo 9fbabc74dSDario Casalinuovo #include <Handler.h> 10b4515980SDario Casalinuovo #include <HttpRequest.h> 11fbabc74dSDario Casalinuovo #include <UrlProtocolRoster.h> 12fbabc74dSDario Casalinuovo 13f8fdf848SAugustin Cavalier #include "MediaDebug.h" 145232a911SBarrett17 15d3630cbaSDario Casalinuovo 16d3630cbaSDario Casalinuovo // 10 seconds timeout 17d3630cbaSDario Casalinuovo #define HTTP_TIMEOUT 10000000 18fbabc74dSDario Casalinuovo 19*ac4b8373SNiels Sascha Reedijk using namespace BPrivate::Network; 20*ac4b8373SNiels Sascha Reedijk 21fbabc74dSDario Casalinuovo 22ff5c2dc2SAdrien Destugues class FileListener : public BUrlProtocolListener { 23fbabc74dSDario Casalinuovo public: 24be2c0725SDario Casalinuovo FileListener(HTTPMediaIO* owner) 25fbabc74dSDario Casalinuovo : 26ff5c2dc2SAdrien Destugues BUrlProtocolListener(), 27fbabc74dSDario Casalinuovo fRequest(NULL), 28f1c771f8SDario Casalinuovo fAdapterIO(owner), 29b4515980SDario Casalinuovo fInitSem(-1), 30b4515980SDario Casalinuovo fRunning(false) 31fbabc74dSDario Casalinuovo { 32fbabc74dSDario Casalinuovo fInputAdapter = fAdapterIO->BuildInputAdapter(); 33d3630cbaSDario Casalinuovo fInitSem = create_sem(0, "http_streamer init sem"); 34fbabc74dSDario Casalinuovo } 35fbabc74dSDario Casalinuovo 363ff901acSDario Casalinuovo virtual ~FileListener() 373ff901acSDario Casalinuovo { 383ff901acSDario Casalinuovo _ReleaseInit(); 393ff901acSDario Casalinuovo } 40fbabc74dSDario Casalinuovo 41fbabc74dSDario Casalinuovo bool ConnectionSuccessful() const 42fbabc74dSDario Casalinuovo { 43fbabc74dSDario Casalinuovo return fRequest != NULL; 44fbabc74dSDario Casalinuovo } 45fbabc74dSDario Casalinuovo 46fbabc74dSDario Casalinuovo void ConnectionOpened(BUrlRequest* request) 47fbabc74dSDario Casalinuovo { 48fbabc74dSDario Casalinuovo fRequest = request; 49b4515980SDario Casalinuovo fRunning = true; 50fbabc74dSDario Casalinuovo } 51fbabc74dSDario Casalinuovo 5276c469dbSAdrien Destugues void HeadersReceived(BUrlRequest* request, const BUrlResult& result) 53a5b5f896SAdrien Destugues { 54a5b5f896SAdrien Destugues fAdapterIO->UpdateSize(); 55a5b5f896SAdrien Destugues } 56a5b5f896SAdrien Destugues 57fbabc74dSDario Casalinuovo void DataReceived(BUrlRequest* request, const char* data, 58fbabc74dSDario Casalinuovo off_t position, ssize_t size) 59fbabc74dSDario Casalinuovo { 603ff901acSDario Casalinuovo if (request != fRequest) { 61fbabc74dSDario Casalinuovo delete request; 623ff901acSDario Casalinuovo return; 633ff901acSDario Casalinuovo } 64fbabc74dSDario Casalinuovo 65b4515980SDario Casalinuovo BHttpRequest* httpReq = dynamic_cast<BHttpRequest*>(request); 66b4515980SDario Casalinuovo if (httpReq != NULL) { 674e793dddSDario Casalinuovo const BHttpResult& httpRes 684e793dddSDario Casalinuovo = (const BHttpResult&)httpReq->Result(); 69b4515980SDario Casalinuovo int32 status = httpRes.StatusCode(); 70b4515980SDario Casalinuovo if (BHttpRequest::IsClientErrorStatusCode(status) 71b4515980SDario Casalinuovo || BHttpRequest::IsServerErrorStatusCode(status)) { 72b4515980SDario Casalinuovo fRunning = false; 73b4515980SDario Casalinuovo } else if (BHttpRequest::IsRedirectionStatusCode(status)) 74b4515980SDario Casalinuovo return; 75b4515980SDario Casalinuovo } 76b4515980SDario Casalinuovo 77b4515980SDario Casalinuovo _ReleaseInit(); 78b4515980SDario Casalinuovo 79fbabc74dSDario Casalinuovo fInputAdapter->Write(data, size); 80fbabc74dSDario Casalinuovo } 81fbabc74dSDario Casalinuovo 82fbabc74dSDario Casalinuovo void RequestCompleted(BUrlRequest* request, bool success) 83fbabc74dSDario Casalinuovo { 84eed8ce57SDario Casalinuovo _ReleaseInit(); 85eed8ce57SDario Casalinuovo 86fbabc74dSDario Casalinuovo if (request != fRequest) 87fbabc74dSDario Casalinuovo return; 88fbabc74dSDario Casalinuovo 89fbabc74dSDario Casalinuovo fRequest = NULL; 90fbabc74dSDario Casalinuovo } 91fbabc74dSDario Casalinuovo 92d3630cbaSDario Casalinuovo status_t LockOnInit(bigtime_t timeout) 93f1c771f8SDario Casalinuovo { 94d3630cbaSDario Casalinuovo return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout); 95f1c771f8SDario Casalinuovo } 96f1c771f8SDario Casalinuovo 97b4515980SDario Casalinuovo bool IsRunning() 98b4515980SDario Casalinuovo { 99b4515980SDario Casalinuovo return fRunning; 100b4515980SDario Casalinuovo } 101b4515980SDario Casalinuovo 102fbabc74dSDario Casalinuovo private: 103eed8ce57SDario Casalinuovo void _ReleaseInit() 104eed8ce57SDario Casalinuovo { 105eed8ce57SDario Casalinuovo if (fInitSem != -1) { 106eed8ce57SDario Casalinuovo release_sem(fInitSem); 107eed8ce57SDario Casalinuovo delete_sem(fInitSem); 108eed8ce57SDario Casalinuovo fInitSem = -1; 109eed8ce57SDario Casalinuovo } 110eed8ce57SDario Casalinuovo } 111eed8ce57SDario Casalinuovo 112fbabc74dSDario Casalinuovo BUrlRequest* fRequest; 113be2c0725SDario Casalinuovo HTTPMediaIO* fAdapterIO; 114fbabc74dSDario Casalinuovo BInputAdapter* fInputAdapter; 115d3630cbaSDario Casalinuovo sem_id fInitSem; 116b4515980SDario Casalinuovo bool fRunning; 117fbabc74dSDario Casalinuovo }; 118fbabc74dSDario Casalinuovo 119617b62c9SDario Casalinuovo 1200ba82236SDario Casalinuovo HTTPMediaIO::HTTPMediaIO(BUrl url) 121617b62c9SDario Casalinuovo : 1225c05bb48SDario Casalinuovo BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT), 12393a1f9d2SDario Casalinuovo fReq(NULL), 12493a1f9d2SDario Casalinuovo fListener(NULL), 1253ff901acSDario Casalinuovo fReqThread(-1), 126d3630cbaSDario Casalinuovo fUrl(url), 127b4e751b8SDario Casalinuovo fIsMutable(false) 128617b62c9SDario Casalinuovo { 1293ff901acSDario Casalinuovo CALLED(); 130617b62c9SDario Casalinuovo } 131617b62c9SDario Casalinuovo 132617b62c9SDario Casalinuovo 133617b62c9SDario Casalinuovo HTTPMediaIO::~HTTPMediaIO() 134617b62c9SDario Casalinuovo { 1353ff901acSDario Casalinuovo CALLED(); 1363ff901acSDario Casalinuovo 137af7d48feSAdrien Destugues if (fReq != NULL) { 1383ff901acSDario Casalinuovo fReq->Stop(); 1393ff901acSDario Casalinuovo status_t status; 1403ff901acSDario Casalinuovo wait_for_thread(fReqThread, &status); 1413ff901acSDario Casalinuovo 14298e33bf6SAdrien Destugues delete fReq; 143617b62c9SDario Casalinuovo } 144b2fa4e17SAdrien Destugues } 145617b62c9SDario Casalinuovo 146617b62c9SDario Casalinuovo 147b4e751b8SDario Casalinuovo void 148b4e751b8SDario Casalinuovo HTTPMediaIO::GetFlags(int32* flags) const 149b4e751b8SDario Casalinuovo { 150b4e751b8SDario Casalinuovo *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD; 151b4e751b8SDario Casalinuovo if (fIsMutable) 152b4e751b8SDario Casalinuovo *flags = *flags | B_MEDIA_MUTABLE_SIZE; 153b4e751b8SDario Casalinuovo } 154b4e751b8SDario Casalinuovo 155b4e751b8SDario Casalinuovo 156617b62c9SDario Casalinuovo ssize_t 157617b62c9SDario Casalinuovo HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size) 158617b62c9SDario Casalinuovo { 159617b62c9SDario Casalinuovo return B_NOT_SUPPORTED; 160617b62c9SDario Casalinuovo } 161f1c771f8SDario Casalinuovo 162f1c771f8SDario Casalinuovo 163f1c771f8SDario Casalinuovo status_t 164f1c771f8SDario Casalinuovo HTTPMediaIO::SetSize(off_t size) 165f1c771f8SDario Casalinuovo { 166f1c771f8SDario Casalinuovo return B_NOT_SUPPORTED; 167f1c771f8SDario Casalinuovo } 168f1c771f8SDario Casalinuovo 169f1c771f8SDario Casalinuovo 170f1c771f8SDario Casalinuovo status_t 17193a1f9d2SDario Casalinuovo HTTPMediaIO::Open() 17293a1f9d2SDario Casalinuovo { 1733ff901acSDario Casalinuovo CALLED(); 17493a1f9d2SDario Casalinuovo 17593a1f9d2SDario Casalinuovo fListener = new FileListener(this); 17693a1f9d2SDario Casalinuovo 17798e33bf6SAdrien Destugues fReq = BUrlProtocolRoster::MakeRequest(fUrl, fListener); 17893a1f9d2SDario Casalinuovo 17993a1f9d2SDario Casalinuovo if (fReq == NULL) 18093a1f9d2SDario Casalinuovo return B_ERROR; 18193a1f9d2SDario Casalinuovo 182be2c0725SDario Casalinuovo fReqThread = fReq->Run(); 183be2c0725SDario Casalinuovo if (fReqThread < 0) 18493a1f9d2SDario Casalinuovo return B_ERROR; 18593a1f9d2SDario Casalinuovo 186d3630cbaSDario Casalinuovo status_t ret = fListener->LockOnInit(HTTP_TIMEOUT); 187d3630cbaSDario Casalinuovo if (ret != B_OK) 188d3630cbaSDario Casalinuovo return ret; 189d3630cbaSDario Casalinuovo 19093a1f9d2SDario Casalinuovo return BAdapterIO::Open(); 19193a1f9d2SDario Casalinuovo } 19293a1f9d2SDario Casalinuovo 19393a1f9d2SDario Casalinuovo 194eed8ce57SDario Casalinuovo bool 195eed8ce57SDario Casalinuovo HTTPMediaIO::IsRunning() const 196eed8ce57SDario Casalinuovo { 197e42135e5SDario Casalinuovo if (fListener != NULL) 198b4515980SDario Casalinuovo return fListener->IsRunning(); 199e42135e5SDario Casalinuovo else if (fReq != NULL) 2004e793dddSDario Casalinuovo return fReq->IsRunning(); 201e42135e5SDario Casalinuovo 202e42135e5SDario Casalinuovo return false; 203eed8ce57SDario Casalinuovo } 204eed8ce57SDario Casalinuovo 205eed8ce57SDario Casalinuovo 20693a1f9d2SDario Casalinuovo status_t 20793a1f9d2SDario Casalinuovo HTTPMediaIO::SeekRequested(off_t position) 20893a1f9d2SDario Casalinuovo { 20993a1f9d2SDario Casalinuovo return BAdapterIO::SeekRequested(position); 21093a1f9d2SDario Casalinuovo } 211be2c0725SDario Casalinuovo 212be2c0725SDario Casalinuovo 213be2c0725SDario Casalinuovo void 214be2c0725SDario Casalinuovo HTTPMediaIO::UpdateSize() 215be2c0725SDario Casalinuovo { 216be2c0725SDario Casalinuovo // At this point we decide if our size is fixed or mutable, 217be2c0725SDario Casalinuovo // this will change the behavior of our parent. 218be2c0725SDario Casalinuovo off_t size = fReq->Result().Length(); 219be2c0725SDario Casalinuovo if (size > 0) 220be2c0725SDario Casalinuovo BAdapterIO::SetSize(size); 221be2c0725SDario Casalinuovo else 222be2c0725SDario Casalinuovo fIsMutable = true; 223be2c0725SDario Casalinuovo } 224