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