xref: /haiku/src/add-ons/media/plugins/http_streamer/HTTPMediaIO.cpp (revision ac4b83732861796ceade108bed3e96e337c8c10a)
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>
10b4515980SDario Casalinuovo #include <HttpRequest.h>
11fbabc74dSDario Casalinuovo #include <UrlProtocolRoster.h>
12fbabc74dSDario Casalinuovo 
13f8fdf848SAugustin Cavalier #include "MediaDebug.h"
145232a911SBarrett17 
15d3630cbaSDario Casalinuovo 
16d3630cbaSDario Casalinuovo // 10 seconds timeout
17d3630cbaSDario Casalinuovo #define HTTP_TIMEOUT 10000000
18fbabc74dSDario Casalinuovo 
19*ac4b8373SNiels Sascha Reedijk using namespace BPrivate::Network;
20*ac4b8373SNiels Sascha Reedijk 
21fbabc74dSDario Casalinuovo 
22ff5c2dc2SAdrien Destugues class FileListener : public BUrlProtocolListener {
23fbabc74dSDario Casalinuovo public:
24be2c0725SDario Casalinuovo 		FileListener(HTTPMediaIO* owner)
25fbabc74dSDario Casalinuovo 			:
26ff5c2dc2SAdrien Destugues 			BUrlProtocolListener(),
27fbabc74dSDario Casalinuovo 			fRequest(NULL),
28f1c771f8SDario Casalinuovo 			fAdapterIO(owner),
29b4515980SDario Casalinuovo 			fInitSem(-1),
30b4515980SDario Casalinuovo 			fRunning(false)
31fbabc74dSDario Casalinuovo 		{
32fbabc74dSDario Casalinuovo 			fInputAdapter = fAdapterIO->BuildInputAdapter();
33d3630cbaSDario Casalinuovo 			fInitSem = create_sem(0, "http_streamer init sem");
34fbabc74dSDario Casalinuovo 		}
35fbabc74dSDario Casalinuovo 
363ff901acSDario Casalinuovo 		virtual ~FileListener()
373ff901acSDario Casalinuovo 		{
383ff901acSDario Casalinuovo 			_ReleaseInit();
393ff901acSDario Casalinuovo 		}
40fbabc74dSDario Casalinuovo 
41fbabc74dSDario Casalinuovo 		bool ConnectionSuccessful() const
42fbabc74dSDario Casalinuovo 		{
43fbabc74dSDario Casalinuovo 			return fRequest != NULL;
44fbabc74dSDario Casalinuovo 		}
45fbabc74dSDario Casalinuovo 
46fbabc74dSDario Casalinuovo 		void ConnectionOpened(BUrlRequest* request)
47fbabc74dSDario Casalinuovo 		{
48fbabc74dSDario Casalinuovo 			fRequest = request;
49b4515980SDario Casalinuovo 			fRunning = true;
50fbabc74dSDario Casalinuovo 		}
51fbabc74dSDario Casalinuovo 
5276c469dbSAdrien Destugues 		void HeadersReceived(BUrlRequest* request, const BUrlResult& result)
53a5b5f896SAdrien Destugues 		{
54a5b5f896SAdrien Destugues 			fAdapterIO->UpdateSize();
55a5b5f896SAdrien Destugues 		}
56a5b5f896SAdrien Destugues 
57fbabc74dSDario Casalinuovo 		void DataReceived(BUrlRequest* request, const char* data,
58fbabc74dSDario Casalinuovo 			off_t position, ssize_t size)
59fbabc74dSDario Casalinuovo 		{
603ff901acSDario Casalinuovo 			if (request != fRequest) {
61fbabc74dSDario Casalinuovo 				delete request;
623ff901acSDario Casalinuovo 				return;
633ff901acSDario Casalinuovo 			}
64fbabc74dSDario Casalinuovo 
65b4515980SDario Casalinuovo 			BHttpRequest* httpReq = dynamic_cast<BHttpRequest*>(request);
66b4515980SDario Casalinuovo 			if (httpReq != NULL) {
674e793dddSDario Casalinuovo 				const BHttpResult& httpRes
684e793dddSDario Casalinuovo 					= (const BHttpResult&)httpReq->Result();
69b4515980SDario Casalinuovo 				int32 status = httpRes.StatusCode();
70b4515980SDario Casalinuovo 				if (BHttpRequest::IsClientErrorStatusCode(status)
71b4515980SDario Casalinuovo 						|| BHttpRequest::IsServerErrorStatusCode(status)) {
72b4515980SDario Casalinuovo 					fRunning = false;
73b4515980SDario Casalinuovo 				} else if (BHttpRequest::IsRedirectionStatusCode(status))
74b4515980SDario Casalinuovo 					return;
75b4515980SDario Casalinuovo 			}
76b4515980SDario Casalinuovo 
77b4515980SDario Casalinuovo 			_ReleaseInit();
78b4515980SDario Casalinuovo 
79fbabc74dSDario Casalinuovo 			fInputAdapter->Write(data, size);
80fbabc74dSDario Casalinuovo 		}
81fbabc74dSDario Casalinuovo 
82fbabc74dSDario Casalinuovo 		void RequestCompleted(BUrlRequest* request, bool success)
83fbabc74dSDario Casalinuovo 		{
84eed8ce57SDario Casalinuovo 			_ReleaseInit();
85eed8ce57SDario Casalinuovo 
86fbabc74dSDario Casalinuovo 			if (request != fRequest)
87fbabc74dSDario Casalinuovo 				return;
88fbabc74dSDario Casalinuovo 
89fbabc74dSDario Casalinuovo 			fRequest = NULL;
90fbabc74dSDario Casalinuovo 		}
91fbabc74dSDario Casalinuovo 
92d3630cbaSDario Casalinuovo 		status_t LockOnInit(bigtime_t timeout)
93f1c771f8SDario Casalinuovo 		{
94d3630cbaSDario Casalinuovo 			return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout);
95f1c771f8SDario Casalinuovo 		}
96f1c771f8SDario Casalinuovo 
97b4515980SDario Casalinuovo 		bool IsRunning()
98b4515980SDario Casalinuovo 		{
99b4515980SDario Casalinuovo 			return fRunning;
100b4515980SDario Casalinuovo 		}
101b4515980SDario Casalinuovo 
102fbabc74dSDario Casalinuovo private:
103eed8ce57SDario Casalinuovo 		void _ReleaseInit()
104eed8ce57SDario Casalinuovo 		{
105eed8ce57SDario Casalinuovo 			if (fInitSem != -1) {
106eed8ce57SDario Casalinuovo 				release_sem(fInitSem);
107eed8ce57SDario Casalinuovo 				delete_sem(fInitSem);
108eed8ce57SDario Casalinuovo 				fInitSem = -1;
109eed8ce57SDario Casalinuovo 			}
110eed8ce57SDario Casalinuovo 		}
111eed8ce57SDario Casalinuovo 
112fbabc74dSDario Casalinuovo 		BUrlRequest*	fRequest;
113be2c0725SDario Casalinuovo 		HTTPMediaIO*	fAdapterIO;
114fbabc74dSDario Casalinuovo 		BInputAdapter*	fInputAdapter;
115d3630cbaSDario Casalinuovo 		sem_id			fInitSem;
116b4515980SDario Casalinuovo 		bool			fRunning;
117fbabc74dSDario Casalinuovo };
118fbabc74dSDario Casalinuovo 
119617b62c9SDario Casalinuovo 
1200ba82236SDario Casalinuovo HTTPMediaIO::HTTPMediaIO(BUrl url)
121617b62c9SDario Casalinuovo 	:
1225c05bb48SDario Casalinuovo 	BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT),
12393a1f9d2SDario Casalinuovo 	fReq(NULL),
12493a1f9d2SDario Casalinuovo 	fListener(NULL),
1253ff901acSDario Casalinuovo 	fReqThread(-1),
126d3630cbaSDario Casalinuovo 	fUrl(url),
127b4e751b8SDario Casalinuovo 	fIsMutable(false)
128617b62c9SDario Casalinuovo {
1293ff901acSDario Casalinuovo 	CALLED();
130617b62c9SDario Casalinuovo }
131617b62c9SDario Casalinuovo 
132617b62c9SDario Casalinuovo 
133617b62c9SDario Casalinuovo HTTPMediaIO::~HTTPMediaIO()
134617b62c9SDario Casalinuovo {
1353ff901acSDario Casalinuovo 	CALLED();
1363ff901acSDario Casalinuovo 
137af7d48feSAdrien Destugues 	if (fReq != NULL) {
1383ff901acSDario Casalinuovo 		fReq->Stop();
1393ff901acSDario Casalinuovo 		status_t status;
1403ff901acSDario Casalinuovo 		wait_for_thread(fReqThread, &status);
1413ff901acSDario Casalinuovo 
14298e33bf6SAdrien Destugues 		delete fReq;
143617b62c9SDario Casalinuovo 	}
144b2fa4e17SAdrien Destugues }
145617b62c9SDario Casalinuovo 
146617b62c9SDario Casalinuovo 
147b4e751b8SDario Casalinuovo void
148b4e751b8SDario Casalinuovo HTTPMediaIO::GetFlags(int32* flags) const
149b4e751b8SDario Casalinuovo {
150b4e751b8SDario Casalinuovo 	*flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD;
151b4e751b8SDario Casalinuovo 	if (fIsMutable)
152b4e751b8SDario Casalinuovo 		*flags = *flags | B_MEDIA_MUTABLE_SIZE;
153b4e751b8SDario Casalinuovo }
154b4e751b8SDario Casalinuovo 
155b4e751b8SDario Casalinuovo 
156617b62c9SDario Casalinuovo ssize_t
157617b62c9SDario Casalinuovo HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
158617b62c9SDario Casalinuovo {
159617b62c9SDario Casalinuovo 	return B_NOT_SUPPORTED;
160617b62c9SDario Casalinuovo }
161f1c771f8SDario Casalinuovo 
162f1c771f8SDario Casalinuovo 
163f1c771f8SDario Casalinuovo status_t
164f1c771f8SDario Casalinuovo HTTPMediaIO::SetSize(off_t size)
165f1c771f8SDario Casalinuovo {
166f1c771f8SDario Casalinuovo 	return B_NOT_SUPPORTED;
167f1c771f8SDario Casalinuovo }
168f1c771f8SDario Casalinuovo 
169f1c771f8SDario Casalinuovo 
170f1c771f8SDario Casalinuovo status_t
17193a1f9d2SDario Casalinuovo HTTPMediaIO::Open()
17293a1f9d2SDario Casalinuovo {
1733ff901acSDario Casalinuovo 	CALLED();
17493a1f9d2SDario Casalinuovo 
17593a1f9d2SDario Casalinuovo 	fListener = new FileListener(this);
17693a1f9d2SDario Casalinuovo 
17798e33bf6SAdrien Destugues 	fReq = BUrlProtocolRoster::MakeRequest(fUrl, fListener);
17893a1f9d2SDario Casalinuovo 
17993a1f9d2SDario Casalinuovo 	if (fReq == NULL)
18093a1f9d2SDario Casalinuovo 		return B_ERROR;
18193a1f9d2SDario Casalinuovo 
182be2c0725SDario Casalinuovo 	fReqThread = fReq->Run();
183be2c0725SDario Casalinuovo 	if (fReqThread < 0)
18493a1f9d2SDario Casalinuovo 		return B_ERROR;
18593a1f9d2SDario Casalinuovo 
186d3630cbaSDario Casalinuovo 	status_t ret = fListener->LockOnInit(HTTP_TIMEOUT);
187d3630cbaSDario Casalinuovo 	if (ret != B_OK)
188d3630cbaSDario Casalinuovo 		return ret;
189d3630cbaSDario Casalinuovo 
19093a1f9d2SDario Casalinuovo 	return BAdapterIO::Open();
19193a1f9d2SDario Casalinuovo }
19293a1f9d2SDario Casalinuovo 
19393a1f9d2SDario Casalinuovo 
194eed8ce57SDario Casalinuovo bool
195eed8ce57SDario Casalinuovo HTTPMediaIO::IsRunning() const
196eed8ce57SDario Casalinuovo {
197e42135e5SDario Casalinuovo 	if (fListener != NULL)
198b4515980SDario Casalinuovo 		return fListener->IsRunning();
199e42135e5SDario Casalinuovo 	else if (fReq != NULL)
2004e793dddSDario Casalinuovo 		return fReq->IsRunning();
201e42135e5SDario Casalinuovo 
202e42135e5SDario Casalinuovo 	return false;
203eed8ce57SDario Casalinuovo }
204eed8ce57SDario Casalinuovo 
205eed8ce57SDario Casalinuovo 
20693a1f9d2SDario Casalinuovo status_t
20793a1f9d2SDario Casalinuovo HTTPMediaIO::SeekRequested(off_t position)
20893a1f9d2SDario Casalinuovo {
20993a1f9d2SDario Casalinuovo 	return BAdapterIO::SeekRequested(position);
21093a1f9d2SDario Casalinuovo }
211be2c0725SDario Casalinuovo 
212be2c0725SDario Casalinuovo 
213be2c0725SDario Casalinuovo void
214be2c0725SDario Casalinuovo HTTPMediaIO::UpdateSize()
215be2c0725SDario Casalinuovo {
216be2c0725SDario Casalinuovo 	// At this point we decide if our size is fixed or mutable,
217be2c0725SDario Casalinuovo 	// this will change the behavior of our parent.
218be2c0725SDario Casalinuovo 	off_t size = fReq->Result().Length();
219be2c0725SDario Casalinuovo 	if (size > 0)
220be2c0725SDario Casalinuovo 		BAdapterIO::SetSize(size);
221be2c0725SDario Casalinuovo 	else
222be2c0725SDario Casalinuovo 		fIsMutable = true;
223be2c0725SDario Casalinuovo }
224