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
19class RelativePositionIO : public BPositionIO {
20public:
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 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
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
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
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
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
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
146	virtual off_t Position() const
147	{
148		AutoReadLocker _(fLock);
149
150		return _RelativeToPosition(fBuffer->Position());
151	}
152
153	virtual	status_t SetSize(off_t size)
154	{
155		AutoWriteLocker _(fLock);
156
157		return fBuffer->SetSize(_PositionToRelative(size));
158	}
159
160	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
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
180	void SetBuffer(BPositionIO* buffer)
181	{
182		delete fBuffer;
183		fBuffer = buffer;
184	}
185
186	bool IsStreaming() const
187	{
188		int32 flags = 0;
189		fOwner->GetFlags(&flags);
190		return ((flags & B_MEDIA_STREAMING) == B_MEDIA_STREAMING);
191	}
192
193	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
200	bool IsSeekable() const
201	{
202		int32 flags = 0;
203		fOwner->GetFlags(&flags);
204		return ((flags & B_MEDIA_SEEKABLE) == B_MEDIA_SEEKABLE);
205	}
206
207	const BPositionIO* Buffer() const
208	{
209		return fBuffer;
210	}
211
212private:
213
214	off_t _PositionToRelative(off_t position) const
215	{
216		return position - fStartOffset;
217	}
218
219	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
236BAdapterIO::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
251BAdapterIO::BAdapterIO(const BAdapterIO &)
252{
253	// copying not allowed...
254}
255
256
257BAdapterIO::~BAdapterIO()
258{
259	CALLED();
260
261	delete fInputAdapter;
262	delete fBuffer;
263}
264
265
266void
267BAdapterIO::GetFlags(int32* flags) const
268{
269	CALLED();
270
271	*flags = fFlags;
272}
273
274
275ssize_t
276BAdapterIO::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
288ssize_t
289BAdapterIO::WriteAt(off_t position, const void* buffer, size_t size)
290{
291	CALLED();
292
293	return fBuffer->WriteAt(position, buffer, size);
294}
295
296
297off_t
298BAdapterIO::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
335off_t
336BAdapterIO::Position() const
337{
338	CALLED();
339
340	return fBuffer->Position();
341}
342
343
344status_t
345BAdapterIO::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
358status_t
359BAdapterIO::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
372status_t
373BAdapterIO::Open()
374{
375	CALLED();
376
377	fOpened = true;
378	return B_OK;
379}
380
381
382bool
383BAdapterIO::IsRunning() const
384{
385	return fOpened;
386}
387
388
389void
390BAdapterIO::SeekCompleted()
391{
392	CALLED();
393	release_sem(fSeekSem);
394	delete_sem(fSeekSem);
395	fSeekSem = -1;
396}
397
398
399status_t
400BAdapterIO::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
412status_t
413BAdapterIO::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
422BInputAdapter*
423BAdapterIO::BuildInputAdapter()
424{
425	if (fInputAdapter != NULL)
426		return fInputAdapter;
427
428	fInputAdapter = new BInputAdapter(this);
429	return fInputAdapter;
430}
431
432
433status_t
434BAdapterIO::SeekRequested(off_t position)
435{
436	CALLED();
437
438	return B_ERROR;
439}
440
441
442ssize_t
443BAdapterIO::BackWrite(const void* buffer, size_t size)
444{
445	return fBuffer->BackWrite(buffer, size);
446}
447
448
449status_t
450BAdapterIO::_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
474BInputAdapter::BInputAdapter(BAdapterIO* io)
475	:
476	fIO(io)
477{
478}
479
480
481BInputAdapter::~BInputAdapter()
482{
483}
484
485
486ssize_t
487BInputAdapter::Write(const void* buffer, size_t size)
488{
489	return fIO->BackWrite(buffer, size);
490}
491
492
493// FBC
494void BAdapterIO::_ReservedAdapterIO1() {}
495void BAdapterIO::_ReservedAdapterIO2() {}
496void BAdapterIO::_ReservedAdapterIO3() {}
497void BAdapterIO::_ReservedAdapterIO4() {}
498void BAdapterIO::_ReservedAdapterIO5() {}
499
500void BInputAdapter::_ReservedInputAdapter1() {}
501void BInputAdapter::_ReservedInputAdapter2() {}
502