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> 10fbabc74dSDario Casalinuovo #include <UrlProtocolRoster.h> 11fbabc74dSDario Casalinuovo 12d3630cbaSDario Casalinuovo 13d3630cbaSDario Casalinuovo // 10 seconds timeout 14d3630cbaSDario Casalinuovo #define HTTP_TIMEOUT 10000000 15fbabc74dSDario Casalinuovo 16fbabc74dSDario Casalinuovo 171acb1f50SDario Casalinuovo class FileListener : public BUrlProtocolAsynchronousListener { 18fbabc74dSDario Casalinuovo public: 19fbabc74dSDario Casalinuovo FileListener(BAdapterIO* owner) 20fbabc74dSDario Casalinuovo : 21fbabc74dSDario Casalinuovo BUrlProtocolAsynchronousListener(true), 22fbabc74dSDario Casalinuovo fRequest(NULL), 23f1c771f8SDario Casalinuovo fAdapterIO(owner), 24d3630cbaSDario Casalinuovo fInitSem(-1) 25fbabc74dSDario Casalinuovo { 26fbabc74dSDario Casalinuovo fInputAdapter = fAdapterIO->BuildInputAdapter(); 27d3630cbaSDario Casalinuovo fInitSem = create_sem(0, "http_streamer init sem"); 28fbabc74dSDario Casalinuovo } 29fbabc74dSDario Casalinuovo 30fbabc74dSDario Casalinuovo virtual ~FileListener() {}; 31fbabc74dSDario Casalinuovo 32fbabc74dSDario Casalinuovo bool ConnectionSuccessful() const 33fbabc74dSDario Casalinuovo { 34fbabc74dSDario Casalinuovo return fRequest != NULL; 35fbabc74dSDario Casalinuovo } 36fbabc74dSDario Casalinuovo 37fbabc74dSDario Casalinuovo void ConnectionOpened(BUrlRequest* request) 38fbabc74dSDario Casalinuovo { 39fbabc74dSDario Casalinuovo if (fRequest != NULL) 40fbabc74dSDario Casalinuovo fRequest->Stop(); 41fbabc74dSDario Casalinuovo 42fbabc74dSDario Casalinuovo fRequest = request; 43fbabc74dSDario Casalinuovo } 44fbabc74dSDario Casalinuovo 45fbabc74dSDario Casalinuovo void DataReceived(BUrlRequest* request, const char* data, 46fbabc74dSDario Casalinuovo off_t position, ssize_t size) 47fbabc74dSDario Casalinuovo { 48d3630cbaSDario Casalinuovo if (fInitSem != -1) { 49d3630cbaSDario Casalinuovo release_sem(fInitSem); 50d3630cbaSDario Casalinuovo delete_sem(fInitSem); 51d3630cbaSDario Casalinuovo fInitSem = -1; 52d3630cbaSDario Casalinuovo } 53d3630cbaSDario Casalinuovo 54fbabc74dSDario Casalinuovo if (request != fRequest) 55fbabc74dSDario Casalinuovo delete request; 56fbabc74dSDario Casalinuovo 57fbabc74dSDario Casalinuovo fInputAdapter->Write(data, size); 58fbabc74dSDario Casalinuovo } 59fbabc74dSDario Casalinuovo 60fbabc74dSDario Casalinuovo void RequestCompleted(BUrlRequest* request, bool success) 61fbabc74dSDario Casalinuovo { 62fbabc74dSDario Casalinuovo if (request != fRequest) 63fbabc74dSDario Casalinuovo return; 64fbabc74dSDario Casalinuovo 65fbabc74dSDario Casalinuovo fRequest = NULL; 66fbabc74dSDario Casalinuovo delete request; 67fbabc74dSDario Casalinuovo } 68fbabc74dSDario Casalinuovo 69d3630cbaSDario Casalinuovo status_t LockOnInit(bigtime_t timeout) 70f1c771f8SDario Casalinuovo { 71d3630cbaSDario Casalinuovo return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout); 72f1c771f8SDario Casalinuovo } 73f1c771f8SDario Casalinuovo 74fbabc74dSDario Casalinuovo private: 75fbabc74dSDario Casalinuovo BUrlRequest* fRequest; 76fbabc74dSDario Casalinuovo BAdapterIO* fAdapterIO; 77fbabc74dSDario Casalinuovo BInputAdapter* fInputAdapter; 78d3630cbaSDario Casalinuovo sem_id fInitSem; 79fbabc74dSDario Casalinuovo }; 80fbabc74dSDario Casalinuovo 81617b62c9SDario Casalinuovo 820ba82236SDario Casalinuovo HTTPMediaIO::HTTPMediaIO(BUrl url) 83617b62c9SDario Casalinuovo : 84*5c05bb48SDario Casalinuovo BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT), 8593a1f9d2SDario Casalinuovo fContext(NULL), 8693a1f9d2SDario Casalinuovo fReq(NULL), 8793a1f9d2SDario Casalinuovo fListener(NULL), 88d3630cbaSDario Casalinuovo fUrl(url), 89b4e751b8SDario Casalinuovo fIsMutable(false) 90617b62c9SDario Casalinuovo { 91617b62c9SDario Casalinuovo } 92617b62c9SDario Casalinuovo 93617b62c9SDario Casalinuovo 94617b62c9SDario Casalinuovo HTTPMediaIO::~HTTPMediaIO() 95617b62c9SDario Casalinuovo { 96617b62c9SDario Casalinuovo } 97617b62c9SDario Casalinuovo 98617b62c9SDario Casalinuovo 99b4e751b8SDario Casalinuovo void 100b4e751b8SDario Casalinuovo HTTPMediaIO::GetFlags(int32* flags) const 101b4e751b8SDario Casalinuovo { 102b4e751b8SDario Casalinuovo *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD; 103b4e751b8SDario Casalinuovo if (fIsMutable) 104b4e751b8SDario Casalinuovo *flags = *flags | B_MEDIA_MUTABLE_SIZE; 105b4e751b8SDario Casalinuovo } 106b4e751b8SDario Casalinuovo 107b4e751b8SDario Casalinuovo 108617b62c9SDario Casalinuovo ssize_t 109617b62c9SDario Casalinuovo HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size) 110617b62c9SDario Casalinuovo { 111617b62c9SDario Casalinuovo return B_NOT_SUPPORTED; 112617b62c9SDario Casalinuovo } 113f1c771f8SDario Casalinuovo 114f1c771f8SDario Casalinuovo 115f1c771f8SDario Casalinuovo status_t 116f1c771f8SDario Casalinuovo HTTPMediaIO::SetSize(off_t size) 117f1c771f8SDario Casalinuovo { 118f1c771f8SDario Casalinuovo return B_NOT_SUPPORTED; 119f1c771f8SDario Casalinuovo } 120f1c771f8SDario Casalinuovo 121f1c771f8SDario Casalinuovo 122f1c771f8SDario Casalinuovo status_t 12393a1f9d2SDario Casalinuovo HTTPMediaIO::Open() 12493a1f9d2SDario Casalinuovo { 12593a1f9d2SDario Casalinuovo fContext = new BUrlContext(); 12693a1f9d2SDario Casalinuovo fContext->AcquireReference(); 12793a1f9d2SDario Casalinuovo 12893a1f9d2SDario Casalinuovo fListener = new FileListener(this); 12993a1f9d2SDario Casalinuovo 13093a1f9d2SDario Casalinuovo fReq = BUrlProtocolRoster::MakeRequest(fUrl, 13193a1f9d2SDario Casalinuovo fListener, fContext); 13293a1f9d2SDario Casalinuovo 13393a1f9d2SDario Casalinuovo if (fReq == NULL) 13493a1f9d2SDario Casalinuovo return B_ERROR; 13593a1f9d2SDario Casalinuovo 13693a1f9d2SDario Casalinuovo if (fReq->Run() < 0) 13793a1f9d2SDario Casalinuovo return B_ERROR; 13893a1f9d2SDario Casalinuovo 139d3630cbaSDario Casalinuovo status_t ret = fListener->LockOnInit(HTTP_TIMEOUT); 140d3630cbaSDario Casalinuovo if (ret != B_OK) 141d3630cbaSDario Casalinuovo return ret; 142d3630cbaSDario Casalinuovo 143b4e751b8SDario Casalinuovo off_t totalSize = fReq->Result().Length(); 144b4e751b8SDario Casalinuovo 145b4e751b8SDario Casalinuovo // At this point we decide if our size is fixed or mutable, 146b4e751b8SDario Casalinuovo // this will change the behavior of our parent. 147b4e751b8SDario Casalinuovo if (totalSize > 0) 148b4e751b8SDario Casalinuovo BAdapterIO::SetSize(totalSize); 149b4e751b8SDario Casalinuovo else 150b4e751b8SDario Casalinuovo fIsMutable = true; 151d3630cbaSDario Casalinuovo 15293a1f9d2SDario Casalinuovo return BAdapterIO::Open(); 15393a1f9d2SDario Casalinuovo } 15493a1f9d2SDario Casalinuovo 15593a1f9d2SDario Casalinuovo 15693a1f9d2SDario Casalinuovo void 15793a1f9d2SDario Casalinuovo HTTPMediaIO::Close() 15893a1f9d2SDario Casalinuovo { 15993a1f9d2SDario Casalinuovo delete fReq; 16093a1f9d2SDario Casalinuovo delete fListener; 16193a1f9d2SDario Casalinuovo 16293a1f9d2SDario Casalinuovo fContext->ReleaseReference(); 16393a1f9d2SDario Casalinuovo delete fContext; 16493a1f9d2SDario Casalinuovo 16593a1f9d2SDario Casalinuovo BAdapterIO::Close(); 16693a1f9d2SDario Casalinuovo } 16793a1f9d2SDario Casalinuovo 16893a1f9d2SDario Casalinuovo 16993a1f9d2SDario Casalinuovo status_t 17093a1f9d2SDario Casalinuovo HTTPMediaIO::SeekRequested(off_t position) 17193a1f9d2SDario Casalinuovo { 17293a1f9d2SDario Casalinuovo return BAdapterIO::SeekRequested(position); 17393a1f9d2SDario Casalinuovo } 174