xref: /haiku/src/add-ons/media/plugins/http_streamer/HTTPMediaIO.cpp (revision 2ca1376080f866aafba1edc95eaa036b92ed2078)
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:
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 
36 		virtual ~FileListener()
37 		{
38 			_ReleaseInit();
39 		}
40 
41 		bool ConnectionSuccessful() const
42 		{
43 			return fRequest != NULL;
44 		}
45 
46 		void ConnectionOpened(BUrlRequest* request)
47 		{
48 			fRequest = request;
49 			fRunning = true;
50 		}
51 
52 		void HeadersReceived(BUrlRequest* request)
53 		{
54 			if (request != fRequest) {
55 				delete request;
56 				return;
57 			}
58 
59 			fAdapterIO->UpdateSize();
60 		}
61 
62 		void RequestCompleted(BUrlRequest* request, bool success)
63 		{
64 			_ReleaseInit();
65 
66 			if (request != fRequest)
67 				return;
68 
69 			fRequest = NULL;
70 		}
71 
72 		ssize_t Write(const void* data, size_t size)
73 		{
74 			_ReleaseInit();
75 
76 			return fInputAdapter->Write(data, size);
77 		}
78 
79 		status_t LockOnInit(bigtime_t timeout)
80 		{
81 			return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout);
82 		}
83 
84 		bool IsRunning()
85 		{
86 			return fRunning;
87 		}
88 
89 private:
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 
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 
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
135 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
144 HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
145 {
146 	return B_NOT_SUPPORTED;
147 }
148 
149 
150 status_t
151 HTTPMediaIO::SetSize(off_t size)
152 {
153 	return B_NOT_SUPPORTED;
154 }
155 
156 
157 status_t
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
186 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
198 HTTPMediaIO::SeekRequested(off_t position)
199 {
200 	return BAdapterIO::SeekRequested(position);
201 }
202 
203 
204 void
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