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