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