xref: /haiku/src/kits/media/experimental/AdapterIO.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
1 /*
2  * Copyright 2016 Dario Casalinuovo. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  */
6 
7 #include "AdapterIO.h"
8 
9 #include <MediaIO.h>
10 
11 #include <string.h>
12 
13 #include "debug.h"
14 
15 
16 #define TIMEOUT_QUANTA 100000
17 
18 
19 class RelativePositionIO : public BPositionIO {
20 public:
21 	RelativePositionIO(BAdapterIO* owner, BPositionIO* buffer,
22 		bigtime_t timeout)
23 		:
24 		BPositionIO(),
25 		fOwner(owner),
26 		fBackPosition(0),
27 		fStartOffset(0),
28 		fBuffer(buffer),
29 		fTimeout(timeout)
30 	{
31 	}
32 
33 	virtual	~RelativePositionIO()
34 	{
35 		delete fBuffer;
36 	}
37 
38 	status_t ResetStartOffset(off_t offset)
39 	{
40 		status_t ret = fBuffer->SetSize(0);
41 		if (ret != B_OK)
42 			return ret;
43 
44 		fBackPosition = 0;
45 		fStartOffset = offset;
46 		return B_OK;
47 	}
48 
49 	status_t EvaluatePosition(off_t position, off_t totalSize)
50 	{
51 		if (position < 0)
52 			return B_ERROR;
53 
54 		if (position < fStartOffset)
55 			return B_RESOURCE_UNAVAILABLE;
56 
57 		if (totalSize > 0 && position > totalSize) {
58 			// This is an endless stream, we don't know
59 			// how much data will come and when, we could
60 			// block on that.
61 			if (IsMutable())
62 				return B_WOULD_BLOCK;
63 			else
64 				return B_ERROR;
65 		}
66 
67 		return B_OK;
68 	}
69 
70 	status_t WaitForData(off_t position, off_t size)
71 	{
72 		off_t bufferSize = 0;
73 		status_t ret = GetSize(&bufferSize);
74 		if (ret != B_OK)
75 			return B_ERROR;
76 
77 		bigtime_t totalTimeOut = 0;
78 
79 		while (bufferSize < position + size) {
80 			// We are not running, no luck to receive
81 			// more data, let's return and avoid locking.
82 			if (!fOwner->IsRunning())
83 				return B_NOT_SUPPORTED;
84 
85 			if (fTimeout != B_INFINITE_TIMEOUT && totalTimeOut >= fTimeout)
86 				return B_TIMED_OUT;
87 
88 			snooze(TIMEOUT_QUANTA);
89 
90 			totalTimeOut += TIMEOUT_QUANTA;
91 			GetSize(&bufferSize);
92 		}
93 		return B_OK;
94 	}
95 
96 	virtual	ssize_t	ReadAt(off_t position, void* buffer,
97 		size_t size)
98 	{
99 		AutoReadLocker _(fLock);
100 
101 		return fBuffer->ReadAt(
102 			_PositionToRelative(position), buffer, size);
103 
104 	}
105 
106 	virtual	ssize_t	WriteAt(off_t position,
107 		const void* buffer, size_t size)
108 	{
109 		AutoWriteLocker _(fLock);
110 
111 		return fBuffer->WriteAt(
112 			_PositionToRelative(position), buffer, size);
113 	}
114 
115 	virtual	off_t Seek(off_t position, uint32 seekMode)
116 	{
117 		AutoWriteLocker _(fLock);
118 
119 		return fBuffer->Seek(_PositionToRelative(position), seekMode);
120 	}
121 
122 	virtual off_t Position() const
123 	{
124 		AutoReadLocker _(fLock);
125 
126 		return _RelativeToPosition(fBuffer->Position());
127 	}
128 
129 	virtual	status_t SetSize(off_t size)
130 	{
131 		AutoWriteLocker _(fLock);
132 
133 		return fBuffer->SetSize(_PositionToRelative(size));
134 	}
135 
136 	virtual	status_t GetSize(off_t* size) const
137 	{
138 		AutoReadLocker _(fLock);
139 
140 		// We use the backend position to make our buffer
141 		// independant of that.
142 		*size = _RelativeToPosition(fBackPosition);
143 
144 		return B_OK;
145 	}
146 
147 	ssize_t BackWrite(const void* buffer, size_t size)
148 	{
149 		AutoWriteLocker _(fLock);
150 
151 		off_t ret = fBuffer->WriteAt(fBackPosition, buffer, size);
152 		fBackPosition += ret;
153 		return ret;
154 	}
155 
156 	void SetBuffer(BPositionIO* buffer)
157 	{
158 		delete fBuffer;
159 		fBuffer = buffer;
160 	}
161 
162 	bool IsStreaming() const
163 	{
164 		int32 flags = 0;
165 		fOwner->GetFlags(&flags);
166 		return (flags & B_MEDIA_STREAMING) == true;
167 	}
168 
169 	bool IsMutable() const
170 	{
171 		int32 flags = 0;
172 		fOwner->GetFlags(&flags);
173 		return (flags & B_MEDIA_MUTABLE_SIZE) == true;
174 	}
175 
176 	bool IsSeekable() const
177 	{
178 		int32 flags = 0;
179 		fOwner->GetFlags(&flags);
180 		return (flags & B_MEDIA_SEEKABLE) == true;
181 	}
182 
183 private:
184 
185 	off_t _PositionToRelative(off_t position) const
186 	{
187 		return position - fStartOffset;
188 	}
189 
190 	off_t _RelativeToPosition(off_t position) const
191 	{
192 		return position + fStartOffset;
193 	}
194 
195 	BAdapterIO*			fOwner;
196 	off_t				fBackPosition;
197 	off_t				fStartOffset;
198 
199 	BPositionIO*		fBuffer;
200 
201 	mutable	RWLocker	fLock;
202 
203 	bigtime_t			fTimeout;
204 };
205 
206 
207 BAdapterIO::BAdapterIO(int32 flags, bigtime_t timeout)
208 	:
209 	fFlags(flags),
210 	fBuffer(NULL),
211 	fTotalSize(0),
212 	fOpened(false),
213 	fSeekSem(-1),
214 	fInputAdapter(NULL)
215 {
216 	CALLED();
217 
218 	fBuffer = new RelativePositionIO(this, new BMallocIO(), timeout);
219 }
220 
221 
222 BAdapterIO::BAdapterIO(const BAdapterIO &)
223 {
224 	// copying not allowed...
225 }
226 
227 
228 BAdapterIO::~BAdapterIO()
229 {
230 	CALLED();
231 
232 	delete fInputAdapter;
233 	delete fBuffer;
234 }
235 
236 
237 void
238 BAdapterIO::GetFlags(int32* flags) const
239 {
240 	CALLED();
241 
242 	*flags = fFlags;
243 }
244 
245 
246 ssize_t
247 BAdapterIO::ReadAt(off_t position, void* buffer, size_t size)
248 {
249 	CALLED();
250 
251 	status_t ret = _EvaluateWait(position, size);
252 	if (ret != B_OK)
253 		return ret;
254 
255 	return fBuffer->ReadAt(position, buffer, size);
256 }
257 
258 
259 ssize_t
260 BAdapterIO::WriteAt(off_t position, const void* buffer, size_t size)
261 {
262 	CALLED();
263 
264 	return fBuffer->WriteAt(position, buffer, size);
265 }
266 
267 
268 off_t
269 BAdapterIO::Seek(off_t position, uint32 seekMode)
270 {
271 	CALLED();
272 
273 	off_t absolutePosition = 0;
274 	off_t size = 0;
275 
276 	if (seekMode == SEEK_CUR)
277 		absolutePosition = Position()+position;
278 	else if (seekMode == SEEK_END) {
279 		if (GetSize(&size) != B_OK)
280 			return B_NOT_SUPPORTED;
281 
282 		absolutePosition = size-position;
283 	}
284 
285 	status_t ret = _EvaluateWait(absolutePosition, 0);
286 
287 	if (ret == B_RESOURCE_UNAVAILABLE && fBuffer->IsStreaming()
288 			&& fBuffer->IsSeekable()) {
289 
290 		fSeekSem = create_sem(0, "BAdapterIO seek sem");
291 
292 		if (SeekRequested(absolutePosition) != B_OK)
293 			return B_NOT_SUPPORTED;
294 
295 		TRACE("BAdapterIO::Seek: Locking on backend seek\n");
296 		acquire_sem(fSeekSem);
297 		TRACE("BAdapterIO::Seek: Seek completed!\n");
298 		fBuffer->ResetStartOffset(absolutePosition);
299 	} else if (ret != B_OK)
300 		return B_NOT_SUPPORTED;
301 
302 	return fBuffer->Seek(position, seekMode);
303 }
304 
305 
306 off_t
307 BAdapterIO::Position() const
308 {
309 	CALLED();
310 
311 	return fBuffer->Position();
312 }
313 
314 
315 status_t
316 BAdapterIO::SetSize(off_t size)
317 {
318 	CALLED();
319 
320 	if (!fBuffer->IsMutable()) {
321 		fTotalSize = size;
322 		return B_OK;
323 	}
324 
325 	return fBuffer->SetSize(size);
326 }
327 
328 
329 status_t
330 BAdapterIO::GetSize(off_t* size) const
331 {
332 	CALLED();
333 
334 	if (!fBuffer->IsMutable()) {
335 		*size = fTotalSize;
336 		return B_OK;
337 	}
338 
339 	return fBuffer->GetSize(size);
340 }
341 
342 
343 status_t
344 BAdapterIO::Open()
345 {
346 	CALLED();
347 
348 	fOpened = true;
349 	return B_OK;
350 }
351 
352 
353 bool
354 BAdapterIO::IsRunning() const
355 {
356 	return fOpened;
357 }
358 
359 
360 void
361 BAdapterIO::SeekCompleted()
362 {
363 	CALLED();
364 	release_sem(fSeekSem);
365 	delete_sem(fSeekSem);
366 	fSeekSem = -1;
367 }
368 
369 
370 status_t
371 BAdapterIO::SetBuffer(BPositionIO* buffer)
372 {
373 	// We can't change the buffer while we
374 	// are running.
375 	if (fOpened)
376 		return B_ERROR;
377 
378 	fBuffer->SetBuffer(buffer);
379 	return B_OK;
380 }
381 
382 
383 BInputAdapter*
384 BAdapterIO::BuildInputAdapter()
385 {
386 	if (fInputAdapter != NULL)
387 		return fInputAdapter;
388 
389 	fInputAdapter = new BInputAdapter(this);
390 	return fInputAdapter;
391 }
392 
393 
394 status_t
395 BAdapterIO::SeekRequested(off_t position)
396 {
397 	CALLED();
398 
399 	return B_ERROR;
400 }
401 
402 
403 ssize_t
404 BAdapterIO::BackWrite(const void* buffer, size_t size)
405 {
406 	return fBuffer->BackWrite(buffer, size);
407 }
408 
409 
410 status_t
411 BAdapterIO::_EvaluateWait(off_t pos, off_t size)
412 {
413 	CALLED();
414 
415 	off_t totalSize = 0;
416 	if (GetSize(&totalSize) != B_OK)
417 		TRACE("BAdapterIO::ReadAt: Can't get our size!\n");
418 
419 	TRACE("BAdapterIO::_EvaluateWait TS %" B_PRId64 " P %" B_PRId64
420 		" S %" B_PRId64 "\n", totalSize, pos, size);
421 
422 	status_t err = fBuffer->EvaluatePosition(pos, totalSize);
423 
424 	TRACE("BAdapterIO::_EvaluateWait: %s\n", strerror(err));
425 
426 	if (err != B_OK && err != B_WOULD_BLOCK)
427 		return err;
428 
429 	TRACE("BAdapterIO::_EvaluateWait: waiting for data\n");
430 
431 	return fBuffer->WaitForData(pos, size);
432 }
433 
434 
435 BInputAdapter::BInputAdapter(BAdapterIO* io)
436 	:
437 	fIO(io)
438 {
439 }
440 
441 
442 BInputAdapter::~BInputAdapter()
443 {
444 }
445 
446 
447 ssize_t
448 BInputAdapter::Write(const void* buffer, size_t size)
449 {
450 	return fIO->BackWrite(buffer, size);
451 }
452 
453 
454 // FBC
455 void BAdapterIO::_ReservedAdapterIO1() {}
456 void BAdapterIO::_ReservedAdapterIO2() {}
457 void BAdapterIO::_ReservedAdapterIO3() {}
458 void BAdapterIO::_ReservedAdapterIO4() {}
459 void BAdapterIO::_ReservedAdapterIO5() {}
460 
461 void BInputAdapter::_ReservedInputAdapter1() {}
462 void BInputAdapter::_ReservedInputAdapter2() {}
463