1 /* 2 * Copyright 2016, Dario Casalinuovo 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "HTTPMediaIO.h" 8 9 #include <Handler.h> 10 #include <UrlProtocolRoster.h> 11 12 13 // 10 seconds timeout 14 #define HTTP_TIMEOUT 10000000 15 16 17 class FileListener : public BUrlProtocolAsynchronousListener { 18 public: 19 FileListener(BAdapterIO* owner) 20 : 21 BUrlProtocolAsynchronousListener(true), 22 fRequest(NULL), 23 fAdapterIO(owner), 24 fInitSem(-1) 25 { 26 fInputAdapter = fAdapterIO->BuildInputAdapter(); 27 fInitSem = create_sem(0, "http_streamer init sem"); 28 } 29 30 virtual ~FileListener() {}; 31 32 bool ConnectionSuccessful() const 33 { 34 return fRequest != NULL; 35 } 36 37 void ConnectionOpened(BUrlRequest* request) 38 { 39 if (fRequest != NULL) 40 fRequest->Stop(); 41 42 fRequest = request; 43 } 44 45 void DataReceived(BUrlRequest* request, const char* data, 46 off_t position, ssize_t size) 47 { 48 if (fInitSem != -1) { 49 release_sem(fInitSem); 50 delete_sem(fInitSem); 51 fInitSem = -1; 52 } 53 54 if (request != fRequest) 55 delete request; 56 57 fInputAdapter->Write(data, size); 58 } 59 60 void RequestCompleted(BUrlRequest* request, bool success) 61 { 62 if (request != fRequest) 63 return; 64 65 fRequest = NULL; 66 delete request; 67 } 68 69 status_t LockOnInit(bigtime_t timeout) 70 { 71 return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout); 72 } 73 74 private: 75 BUrlRequest* fRequest; 76 BAdapterIO* fAdapterIO; 77 BInputAdapter* fInputAdapter; 78 sem_id fInitSem; 79 }; 80 81 82 HTTPMediaIO::HTTPMediaIO(BUrl url) 83 : 84 BAdapterIO(HTTP_TIMEOUT), 85 fContext(NULL), 86 fReq(NULL), 87 fListener(NULL), 88 fUrl(url), 89 fIsMutable(false) 90 { 91 } 92 93 94 HTTPMediaIO::~HTTPMediaIO() 95 { 96 } 97 98 99 void 100 HTTPMediaIO::GetFlags(int32* flags) const 101 { 102 *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD; 103 if (fIsMutable) 104 *flags = *flags | B_MEDIA_MUTABLE_SIZE; 105 } 106 107 108 ssize_t 109 HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size) 110 { 111 return B_NOT_SUPPORTED; 112 } 113 114 115 status_t 116 HTTPMediaIO::SetSize(off_t size) 117 { 118 return B_NOT_SUPPORTED; 119 } 120 121 122 status_t 123 HTTPMediaIO::Open() 124 { 125 fContext = new BUrlContext(); 126 fContext->AcquireReference(); 127 128 fListener = new FileListener(this); 129 130 fReq = BUrlProtocolRoster::MakeRequest(fUrl, 131 fListener, fContext); 132 133 if (fReq == NULL) 134 return B_ERROR; 135 136 if (fReq->Run() < 0) 137 return B_ERROR; 138 139 status_t ret = fListener->LockOnInit(HTTP_TIMEOUT); 140 if (ret != B_OK) 141 return ret; 142 143 off_t totalSize = fReq->Result().Length(); 144 145 // At this point we decide if our size is fixed or mutable, 146 // this will change the behavior of our parent. 147 if (totalSize > 0) 148 BAdapterIO::SetSize(totalSize); 149 else 150 fIsMutable = true; 151 152 return BAdapterIO::Open(); 153 } 154 155 156 void 157 HTTPMediaIO::Close() 158 { 159 delete fReq; 160 delete fListener; 161 162 fContext->ReleaseReference(); 163 delete fContext; 164 165 BAdapterIO::Close(); 166 } 167 168 169 status_t 170 HTTPMediaIO::SeekRequested(off_t position) 171 { 172 return BAdapterIO::SeekRequested(position); 173 } 174