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
19ac4b8373SNiels Sascha Reedijk using namespace BPrivate::Network;
20ac4b8373SNiels Sascha Reedijk
21fbabc74dSDario Casalinuovo
22*78b14420SLeorize class FileListener : public BUrlProtocolListener, public BDataIO {
23fbabc74dSDario Casalinuovo public:
FileListener(HTTPMediaIO * owner)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
~FileListener()363ff901acSDario Casalinuovo virtual ~FileListener()
373ff901acSDario Casalinuovo {
383ff901acSDario Casalinuovo _ReleaseInit();
393ff901acSDario Casalinuovo }
40fbabc74dSDario Casalinuovo
ConnectionSuccessful() const41fbabc74dSDario Casalinuovo bool ConnectionSuccessful() const
42fbabc74dSDario Casalinuovo {
43fbabc74dSDario Casalinuovo return fRequest != NULL;
44fbabc74dSDario Casalinuovo }
45fbabc74dSDario Casalinuovo
ConnectionOpened(BUrlRequest * request)46fbabc74dSDario Casalinuovo void ConnectionOpened(BUrlRequest* request)
47fbabc74dSDario Casalinuovo {
48fbabc74dSDario Casalinuovo fRequest = request;
49b4515980SDario Casalinuovo fRunning = true;
50fbabc74dSDario Casalinuovo }
51fbabc74dSDario Casalinuovo
HeadersReceived(BUrlRequest * request)523e27f8d5SLeorize void HeadersReceived(BUrlRequest* request)
53a5b5f896SAdrien Destugues {
543ff901acSDario Casalinuovo if (request != fRequest) {
55fbabc74dSDario Casalinuovo delete request;
563ff901acSDario Casalinuovo return;
573ff901acSDario Casalinuovo }
58fbabc74dSDario Casalinuovo
59*78b14420SLeorize fAdapterIO->UpdateSize();
60fbabc74dSDario Casalinuovo }
61fbabc74dSDario Casalinuovo
RequestCompleted(BUrlRequest * request,bool success)62fbabc74dSDario Casalinuovo void RequestCompleted(BUrlRequest* request, bool success)
63fbabc74dSDario Casalinuovo {
64eed8ce57SDario Casalinuovo _ReleaseInit();
65eed8ce57SDario Casalinuovo
66fbabc74dSDario Casalinuovo if (request != fRequest)
67fbabc74dSDario Casalinuovo return;
68fbabc74dSDario Casalinuovo
69fbabc74dSDario Casalinuovo fRequest = NULL;
70fbabc74dSDario Casalinuovo }
71fbabc74dSDario Casalinuovo
Write(const void * data,size_t size)72*78b14420SLeorize ssize_t Write(const void* data, size_t size)
73*78b14420SLeorize {
74*78b14420SLeorize _ReleaseInit();
75*78b14420SLeorize
76*78b14420SLeorize return fInputAdapter->Write(data, size);
77*78b14420SLeorize }
78*78b14420SLeorize
LockOnInit(bigtime_t timeout)79d3630cbaSDario Casalinuovo status_t LockOnInit(bigtime_t timeout)
80f1c771f8SDario Casalinuovo {
81d3630cbaSDario Casalinuovo return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout);
82f1c771f8SDario Casalinuovo }
83f1c771f8SDario Casalinuovo
IsRunning()84b4515980SDario Casalinuovo bool IsRunning()
85b4515980SDario Casalinuovo {
86b4515980SDario Casalinuovo return fRunning;
87b4515980SDario Casalinuovo }
88b4515980SDario Casalinuovo
89fbabc74dSDario Casalinuovo private:
_ReleaseInit()90eed8ce57SDario Casalinuovo void _ReleaseInit()
91eed8ce57SDario Casalinuovo {
92eed8ce57SDario Casalinuovo if (fInitSem != -1) {
93eed8ce57SDario Casalinuovo release_sem(fInitSem);
94eed8ce57SDario Casalinuovo delete_sem(fInitSem);
95eed8ce57SDario Casalinuovo fInitSem = -1;
96eed8ce57SDario Casalinuovo }
97eed8ce57SDario Casalinuovo }
98eed8ce57SDario Casalinuovo
99fbabc74dSDario Casalinuovo BUrlRequest* fRequest;
100be2c0725SDario Casalinuovo HTTPMediaIO* fAdapterIO;
101fbabc74dSDario Casalinuovo BInputAdapter* fInputAdapter;
102d3630cbaSDario Casalinuovo sem_id fInitSem;
103b4515980SDario Casalinuovo bool fRunning;
104fbabc74dSDario Casalinuovo };
105fbabc74dSDario Casalinuovo
106617b62c9SDario Casalinuovo
HTTPMediaIO(BUrl url)1070ba82236SDario Casalinuovo HTTPMediaIO::HTTPMediaIO(BUrl url)
108617b62c9SDario Casalinuovo :
1095c05bb48SDario Casalinuovo BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT),
11093a1f9d2SDario Casalinuovo fReq(NULL),
11193a1f9d2SDario Casalinuovo fListener(NULL),
1123ff901acSDario Casalinuovo fReqThread(-1),
113d3630cbaSDario Casalinuovo fUrl(url),
114b4e751b8SDario Casalinuovo fIsMutable(false)
115617b62c9SDario Casalinuovo {
1163ff901acSDario Casalinuovo CALLED();
117617b62c9SDario Casalinuovo }
118617b62c9SDario Casalinuovo
119617b62c9SDario Casalinuovo
~HTTPMediaIO()120617b62c9SDario Casalinuovo HTTPMediaIO::~HTTPMediaIO()
121617b62c9SDario Casalinuovo {
1223ff901acSDario Casalinuovo CALLED();
1233ff901acSDario Casalinuovo
124af7d48feSAdrien Destugues if (fReq != NULL) {
1253ff901acSDario Casalinuovo fReq->Stop();
1263ff901acSDario Casalinuovo status_t status;
1273ff901acSDario Casalinuovo wait_for_thread(fReqThread, &status);
1283ff901acSDario Casalinuovo
12998e33bf6SAdrien Destugues delete fReq;
130617b62c9SDario Casalinuovo }
131b2fa4e17SAdrien Destugues }
132617b62c9SDario Casalinuovo
133617b62c9SDario Casalinuovo
134b4e751b8SDario Casalinuovo void
GetFlags(int32 * flags) const135b4e751b8SDario Casalinuovo HTTPMediaIO::GetFlags(int32* flags) const
136b4e751b8SDario Casalinuovo {
137b4e751b8SDario Casalinuovo *flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD;
138b4e751b8SDario Casalinuovo if (fIsMutable)
139b4e751b8SDario Casalinuovo *flags = *flags | B_MEDIA_MUTABLE_SIZE;
140b4e751b8SDario Casalinuovo }
141b4e751b8SDario Casalinuovo
142b4e751b8SDario Casalinuovo
143617b62c9SDario Casalinuovo ssize_t
WriteAt(off_t position,const void * buffer,size_t size)144617b62c9SDario Casalinuovo HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
145617b62c9SDario Casalinuovo {
146617b62c9SDario Casalinuovo return B_NOT_SUPPORTED;
147617b62c9SDario Casalinuovo }
148f1c771f8SDario Casalinuovo
149f1c771f8SDario Casalinuovo
150f1c771f8SDario Casalinuovo status_t
SetSize(off_t size)151f1c771f8SDario Casalinuovo HTTPMediaIO::SetSize(off_t size)
152f1c771f8SDario Casalinuovo {
153f1c771f8SDario Casalinuovo return B_NOT_SUPPORTED;
154f1c771f8SDario Casalinuovo }
155f1c771f8SDario Casalinuovo
156f1c771f8SDario Casalinuovo
157f1c771f8SDario Casalinuovo status_t
Open()15893a1f9d2SDario Casalinuovo HTTPMediaIO::Open()
15993a1f9d2SDario Casalinuovo {
1603ff901acSDario Casalinuovo CALLED();
16193a1f9d2SDario Casalinuovo
16293a1f9d2SDario Casalinuovo fListener = new FileListener(this);
16393a1f9d2SDario Casalinuovo
164*78b14420SLeorize fReq = BUrlProtocolRoster::MakeRequest(fUrl, fListener, fListener);
16593a1f9d2SDario Casalinuovo
16693a1f9d2SDario Casalinuovo if (fReq == NULL)
16793a1f9d2SDario Casalinuovo return B_ERROR;
16893a1f9d2SDario Casalinuovo
169*78b14420SLeorize BHttpRequest* httpReq = dynamic_cast<BHttpRequest*>(fReq);
170*78b14420SLeorize if (httpReq != NULL)
171*78b14420SLeorize httpReq->SetStopOnError(true);
172*78b14420SLeorize
173be2c0725SDario Casalinuovo fReqThread = fReq->Run();
174be2c0725SDario Casalinuovo if (fReqThread < 0)
17593a1f9d2SDario Casalinuovo return B_ERROR;
17693a1f9d2SDario Casalinuovo
177d3630cbaSDario Casalinuovo status_t ret = fListener->LockOnInit(HTTP_TIMEOUT);
178d3630cbaSDario Casalinuovo if (ret != B_OK)
179d3630cbaSDario Casalinuovo return ret;
180d3630cbaSDario Casalinuovo
18193a1f9d2SDario Casalinuovo return BAdapterIO::Open();
18293a1f9d2SDario Casalinuovo }
18393a1f9d2SDario Casalinuovo
18493a1f9d2SDario Casalinuovo
185eed8ce57SDario Casalinuovo bool
IsRunning() const186eed8ce57SDario Casalinuovo HTTPMediaIO::IsRunning() const
187eed8ce57SDario Casalinuovo {
188e42135e5SDario Casalinuovo if (fListener != NULL)
189b4515980SDario Casalinuovo return fListener->IsRunning();
190e42135e5SDario Casalinuovo else if (fReq != NULL)
1914e793dddSDario Casalinuovo return fReq->IsRunning();
192e42135e5SDario Casalinuovo
193e42135e5SDario Casalinuovo return false;
194eed8ce57SDario Casalinuovo }
195eed8ce57SDario Casalinuovo
196eed8ce57SDario Casalinuovo
19793a1f9d2SDario Casalinuovo status_t
SeekRequested(off_t position)19893a1f9d2SDario Casalinuovo HTTPMediaIO::SeekRequested(off_t position)
19993a1f9d2SDario Casalinuovo {
20093a1f9d2SDario Casalinuovo return BAdapterIO::SeekRequested(position);
20193a1f9d2SDario Casalinuovo }
202be2c0725SDario Casalinuovo
203be2c0725SDario Casalinuovo
204be2c0725SDario Casalinuovo void
UpdateSize()205be2c0725SDario Casalinuovo HTTPMediaIO::UpdateSize()
206be2c0725SDario Casalinuovo {
207be2c0725SDario Casalinuovo // At this point we decide if our size is fixed or mutable,
208be2c0725SDario Casalinuovo // this will change the behavior of our parent.
209be2c0725SDario Casalinuovo off_t size = fReq->Result().Length();
210be2c0725SDario Casalinuovo if (size > 0)
211be2c0725SDario Casalinuovo BAdapterIO::SetSize(size);
212be2c0725SDario Casalinuovo else
213be2c0725SDario Casalinuovo fIsMutable = true;
214be2c0725SDario Casalinuovo }
215