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 <HttpRequest.h>
11 #include <UrlProtocolRoster.h>
12
13 #include "MediaDebug.h"
14
15
16 // 10 seconds timeout
17 #define HTTP_TIMEOUT 10000000
18
19 using namespace BPrivate::Network;
20
21
22 class FileListener : public BUrlProtocolListener, public BDataIO {
23 public:
FileListener(HTTPMediaIO * owner)24 FileListener(HTTPMediaIO* owner)
25 :
26 BUrlProtocolListener(),
27 fRequest(NULL),
28 fAdapterIO(owner),
29 fInitSem(-1),
30 fRunning(false)
31 {
32 fInputAdapter = fAdapterIO->BuildInputAdapter();
33 fInitSem = create_sem(0, "http_streamer init sem");
34 }
35
~FileListener()36 virtual ~FileListener()
37 {
38 _ReleaseInit();
39 }
40
ConnectionSuccessful() const41 bool ConnectionSuccessful() const
42 {
43 return fRequest != NULL;
44 }
45
ConnectionOpened(BUrlRequest * request)46 void ConnectionOpened(BUrlRequest* request)
47 {
48 fRequest = request;
49 fRunning = true;
50 }
51
HeadersReceived(BUrlRequest * request)52 void HeadersReceived(BUrlRequest* request)
53 {
54 if (request != fRequest) {
55 delete request;
56 return;
57 }
58
59 fAdapterIO->UpdateSize();
60 }
61
RequestCompleted(BUrlRequest * request,bool success)62 void RequestCompleted(BUrlRequest* request, bool success)
63 {
64 _ReleaseInit();
65
66 if (request != fRequest)
67 return;
68
69 fRequest = NULL;
70 }
71
Write(const void * data,size_t size)72 ssize_t Write(const void* data, size_t size)
73 {
74 _ReleaseInit();
75
76 return fInputAdapter->Write(data, size);
77 }
78
LockOnInit(bigtime_t timeout)79 status_t LockOnInit(bigtime_t timeout)
80 {
81 return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout);
82 }
83
IsRunning()84 bool IsRunning()
85 {
86 return fRunning;
87 }
88
89 private:
_ReleaseInit()90 void _ReleaseInit()
91 {
92 if (fInitSem != -1) {
93 release_sem(fInitSem);
94 delete_sem(fInitSem);
95 fInitSem = -1;
96 }
97 }
98
99 BUrlRequest* fRequest;
100 HTTPMediaIO* fAdapterIO;
101 BInputAdapter* fInputAdapter;
102 sem_id fInitSem;
103 bool fRunning;
104 };
105
106
HTTPMediaIO(BUrl url)107 HTTPMediaIO::HTTPMediaIO(BUrl url)
108 :
109 BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT),
110 fReq(NULL),
111 fListener(NULL),
112 fReqThread(-1),
113 fUrl(url),
114 fIsMutable(false)
115 {
116 CALLED();
117 }
118
119
~HTTPMediaIO()120 HTTPMediaIO::~HTTPMediaIO()
121 {
122 CALLED();
123
124 if (fReq != NULL) {
125 fReq->Stop();
126 status_t status;
127 wait_for_thread(fReqThread, &status);
128
129 delete fReq;
130 }
131 }
132
133
134 void
GetFlags(int32 * flags) const135 HTTPMediaIO::GetFlags(int32* flags) const
136 {
137 *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD;
138 if (fIsMutable)
139 *flags = *flags | B_MEDIA_MUTABLE_SIZE;
140 }
141
142
143 ssize_t
WriteAt(off_t position,const void * buffer,size_t size)144 HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
145 {
146 return B_NOT_SUPPORTED;
147 }
148
149
150 status_t
SetSize(off_t size)151 HTTPMediaIO::SetSize(off_t size)
152 {
153 return B_NOT_SUPPORTED;
154 }
155
156
157 status_t
Open()158 HTTPMediaIO::Open()
159 {
160 CALLED();
161
162 fListener = new FileListener(this);
163
164 fReq = BUrlProtocolRoster::MakeRequest(fUrl, fListener, fListener);
165
166 if (fReq == NULL)
167 return B_ERROR;
168
169 BHttpRequest* httpReq = dynamic_cast<BHttpRequest*>(fReq);
170 if (httpReq != NULL)
171 httpReq->SetStopOnError(true);
172
173 fReqThread = fReq->Run();
174 if (fReqThread < 0)
175 return B_ERROR;
176
177 status_t ret = fListener->LockOnInit(HTTP_TIMEOUT);
178 if (ret != B_OK)
179 return ret;
180
181 return BAdapterIO::Open();
182 }
183
184
185 bool
IsRunning() const186 HTTPMediaIO::IsRunning() const
187 {
188 if (fListener != NULL)
189 return fListener->IsRunning();
190 else if (fReq != NULL)
191 return fReq->IsRunning();
192
193 return false;
194 }
195
196
197 status_t
SeekRequested(off_t position)198 HTTPMediaIO::SeekRequested(off_t position)
199 {
200 return BAdapterIO::SeekRequested(position);
201 }
202
203
204 void
UpdateSize()205 HTTPMediaIO::UpdateSize()
206 {
207 // At this point we decide if our size is fixed or mutable,
208 // this will change the behavior of our parent.
209 off_t size = fReq->Result().Length();
210 if (size > 0)
211 BAdapterIO::SetSize(size);
212 else
213 fIsMutable = true;
214 }
215