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(HTTPMediaIO* 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 fAdapterIO->UpdateSize(); 43 44 fRequest = request; 45 } 46 47 void DataReceived(BUrlRequest* request, const char* data, 48 off_t position, ssize_t size) 49 { 50 _ReleaseInit(); 51 52 if (request != fRequest) 53 delete request; 54 55 fInputAdapter->Write(data, size); 56 } 57 58 void RequestCompleted(BUrlRequest* request, bool success) 59 { 60 _ReleaseInit(); 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 void _ReleaseInit() 76 { 77 if (fInitSem != -1) { 78 release_sem(fInitSem); 79 delete_sem(fInitSem); 80 fInitSem = -1; 81 } 82 } 83 84 BUrlRequest* fRequest; 85 HTTPMediaIO* fAdapterIO; 86 BInputAdapter* fInputAdapter; 87 sem_id fInitSem; 88 }; 89 90 91 HTTPMediaIO::HTTPMediaIO(BUrl url) 92 : 93 BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT), 94 fContext(NULL), 95 fReq(NULL), 96 fReqThread(-1), 97 fListener(NULL), 98 fUrl(url), 99 fIsMutable(false) 100 { 101 } 102 103 104 HTTPMediaIO::~HTTPMediaIO() 105 { 106 } 107 108 109 void 110 HTTPMediaIO::GetFlags(int32* flags) const 111 { 112 *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD; 113 if (fIsMutable) 114 *flags = *flags | B_MEDIA_MUTABLE_SIZE; 115 } 116 117 118 ssize_t 119 HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size) 120 { 121 return B_NOT_SUPPORTED; 122 } 123 124 125 status_t 126 HTTPMediaIO::SetSize(off_t size) 127 { 128 return B_NOT_SUPPORTED; 129 } 130 131 132 status_t 133 HTTPMediaIO::Open() 134 { 135 fContext = new BUrlContext(); 136 fContext->AcquireReference(); 137 138 fListener = new FileListener(this); 139 140 fReq = BUrlProtocolRoster::MakeRequest(fUrl, 141 fListener, fContext); 142 143 if (fReq == NULL) 144 return B_ERROR; 145 146 fReqThread = fReq->Run(); 147 if (fReqThread < 0) 148 return B_ERROR; 149 150 status_t ret = fListener->LockOnInit(HTTP_TIMEOUT); 151 if (ret != B_OK) 152 return ret; 153 154 return BAdapterIO::Open(); 155 } 156 157 158 void 159 HTTPMediaIO::Close() 160 { 161 fReq->Stop(); 162 status_t status; 163 wait_for_thread(fReqThread, &status); 164 165 delete fReq; 166 delete fListener; 167 168 fContext->ReleaseReference(); 169 delete fContext; 170 171 BAdapterIO::Close(); 172 } 173 174 175 bool 176 HTTPMediaIO::IsRunning() const 177 { 178 return fReq != NULL && fReq->IsRunning(); 179 } 180 181 182 status_t 183 HTTPMediaIO::SeekRequested(off_t position) 184 { 185 return BAdapterIO::SeekRequested(position); 186 } 187 188 189 void 190 HTTPMediaIO::UpdateSize() 191 { 192 // At this point we decide if our size is fixed or mutable, 193 // this will change the behavior of our parent. 194 off_t size = fReq->Result().Length(); 195 if (size > 0) 196 BAdapterIO::SetSize(size); 197 else 198 fIsMutable = true; 199 } 200