xref: /haiku/src/kits/media/experimental/AdapterIO.cpp (revision 1322e37a03386ffe6321ca3fbb03bd3c4e443074)
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:
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 		if (seekMode == SEEK_SET)
120 			return fBuffer->Seek(_PositionToRelative(position), seekMode);
121 		return fBuffer->Seek(position, seekMode);
122 	}
123 
124 	virtual off_t Position() const
125 	{
126 		AutoReadLocker _(fLock);
127 
128 		return _RelativeToPosition(fBuffer->Position());
129 	}
130 
131 	virtual	status_t SetSize(off_t size)
132 	{
133 		AutoWriteLocker _(fLock);
134 
135 		return fBuffer->SetSize(_PositionToRelative(size));
136 	}
137 
138 	virtual	status_t GetSize(off_t* size) const
139 	{
140 		AutoReadLocker _(fLock);
141 
142 		// We use the backend position to make our buffer
143 		// independant of that.
144 		*size = _RelativeToPosition(fBackPosition);
145 
146 		return B_OK;
147 	}
148 
149 	ssize_t BackWrite(const void* buffer, size_t size)
150 	{
151 		AutoWriteLocker _(fLock);
152 
153 		off_t ret = fBuffer->WriteAt(fBackPosition, buffer, size);
154 		fBackPosition += ret;
155 		return ret;
156 	}
157 
158 	void SetBuffer(BPositionIO* buffer)
159 	{
160 		delete fBuffer;
161 		fBuffer = buffer;
162 	}
163 
164 	bool IsStreaming() const
165 	{
166 		int32 flags = 0;
167 		fOwner->GetFlags(&flags);
168 		return ((flags & B_MEDIA_STREAMING) == B_MEDIA_STREAMING);
169 	}
170 
171 	bool IsMutable() const
172 	{
173 		int32 flags = 0;
174 		fOwner->GetFlags(&flags);
175 		return ((flags & B_MEDIA_MUTABLE_SIZE) == B_MEDIA_MUTABLE_SIZE);
176 	}
177 
178 	bool IsSeekable() const
179 	{
180 		int32 flags = 0;
181 		fOwner->GetFlags(&flags);
182 		return ((flags & B_MEDIA_SEEKABLE) == B_MEDIA_SEEKABLE);
183 	}
184 
185 private:
186 
187 	off_t _PositionToRelative(off_t position) const
188 	{
189 		return position - fStartOffset;
190 	}
191 
192 	off_t _RelativeToPosition(off_t position) const
193 	{
194 		return position + fStartOffset;
195 	}
196 
197 	BAdapterIO*			fOwner;
198 	off_t				fBackPosition;
199 	off_t				fStartOffset;
200 
201 	BPositionIO*		fBuffer;
202 
203 	mutable	RWLocker	fLock;
204 
205 	bigtime_t			fTimeout;
206 };
207 
208 
209 BAdapterIO::BAdapterIO(int32 flags, bigtime_t timeout)
210 	:
211 	fFlags(flags),
212 	fBuffer(NULL),
213 	fTotalSize(0),
214 	fOpened(false),
215 	fSeekSem(-1),
216 	fInputAdapter(NULL)
217 {
218 	CALLED();
219 
220 	fBuffer = new RelativePositionIO(this, new BMallocIO(), timeout);
221 }
222 
223 
224 BAdapterIO::BAdapterIO(const BAdapterIO &)
225 {
226 	// copying not allowed...
227 }
228 
229 
230 BAdapterIO::~BAdapterIO()
231 {
232 	CALLED();
233 
234 	delete fInputAdapter;
235 	delete fBuffer;
236 }
237 
238 
239 void
240 BAdapterIO::GetFlags(int32* flags) const
241 {
242 	CALLED();
243 
244 	*flags = fFlags;
245 }
246 
247 
248 ssize_t
249 BAdapterIO::ReadAt(off_t position, void* buffer, size_t size)
250 {
251 	CALLED();
252 
253 	status_t ret = _EvaluateWait(position, size);
254 	if (ret != B_OK)
255 		return ret;
256 
257 	return fBuffer->ReadAt(position, buffer, size);
258 }
259 
260 
261 ssize_t
262 BAdapterIO::WriteAt(off_t position, const void* buffer, size_t size)
263 {
264 	CALLED();
265 
266 	return fBuffer->WriteAt(position, buffer, size);
267 }
268 
269 
270 off_t
271 BAdapterIO::Seek(off_t position, uint32 seekMode)
272 {
273 	CALLED();
274 
275 	off_t absolutePosition = 0;
276 	off_t size = 0;
277 
278 	if (seekMode == SEEK_CUR)
279 		absolutePosition = Position()+position;
280 	else if (seekMode == SEEK_END) {
281 		if (GetSize(&size) != B_OK)
282 			return B_NOT_SUPPORTED;
283 
284 		absolutePosition = size-position;
285 	}
286 
287 	status_t ret = _EvaluateWait(absolutePosition, 0);
288 
289 	if (ret == B_RESOURCE_UNAVAILABLE && fBuffer->IsStreaming()
290 			&& fBuffer->IsSeekable()) {
291 
292 		fSeekSem = create_sem(0, "BAdapterIO seek sem");
293 
294 		if (SeekRequested(absolutePosition) != B_OK)
295 			return B_NOT_SUPPORTED;
296 
297 		TRACE("BAdapterIO::Seek: Locking on backend seek\n");
298 		acquire_sem(fSeekSem);
299 		TRACE("BAdapterIO::Seek: Seek completed!\n");
300 		fBuffer->ResetStartOffset(absolutePosition);
301 	} else if (ret != B_OK)
302 		return B_NOT_SUPPORTED;
303 
304 	return fBuffer->Seek(position, seekMode);
305 }
306 
307 
308 off_t
309 BAdapterIO::Position() const
310 {
311 	CALLED();
312 
313 	return fBuffer->Position();
314 }
315 
316 
317 status_t
318 BAdapterIO::SetSize(off_t size)
319 {
320 	CALLED();
321 
322 	if (!fBuffer->IsMutable()) {
323 		fTotalSize = size;
324 		return B_OK;
325 	}
326 
327 	return fBuffer->SetSize(size);
328 }
329 
330 
331 status_t
332 BAdapterIO::GetSize(off_t* size) const
333 {
334 	CALLED();
335 
336 	if (!fBuffer->IsMutable()) {
337 		*size = fTotalSize;
338 		return B_OK;
339 	}
340 
341 	return fBuffer->GetSize(size);
342 }
343 
344 
345 status_t
346 BAdapterIO::Open()
347 {
348 	CALLED();
349 
350 	fOpened = true;
351 	return B_OK;
352 }
353 
354 
355 bool
356 BAdapterIO::IsRunning() const
357 {
358 	return fOpened;
359 }
360 
361 
362 void
363 BAdapterIO::SeekCompleted()
364 {
365 	CALLED();
366 	release_sem(fSeekSem);
367 	delete_sem(fSeekSem);
368 	fSeekSem = -1;
369 }
370 
371 
372 status_t
373 BAdapterIO::SetBuffer(BPositionIO* buffer)
374 {
375 	// We can't change the buffer while we
376 	// are running.
377 	if (fOpened)
378 		return B_ERROR;
379 
380 	fBuffer->SetBuffer(buffer);
381 	return B_OK;
382 }
383 
384 
385 BInputAdapter*
386 BAdapterIO::BuildInputAdapter()
387 {
388 	if (fInputAdapter != NULL)
389 		return fInputAdapter;
390 
391 	fInputAdapter = new BInputAdapter(this);
392 	return fInputAdapter;
393 }
394 
395 
396 status_t
397 BAdapterIO::SeekRequested(off_t position)
398 {
399 	CALLED();
400 
401 	return B_ERROR;
402 }
403 
404 
405 ssize_t
406 BAdapterIO::BackWrite(const void* buffer, size_t size)
407 {
408 	return fBuffer->BackWrite(buffer, size);
409 }
410 
411 
412 status_t
413 BAdapterIO::_EvaluateWait(off_t pos, off_t size)
414 {
415 	CALLED();
416 
417 	off_t totalSize = 0;
418 	if (GetSize(&totalSize) != B_OK)
419 		TRACE("BAdapterIO::ReadAt: Can't get our size!\n");
420 
421 	TRACE("BAdapterIO::_EvaluateWait TS %" B_PRId64 " P %" B_PRId64
422 		" S %" B_PRId64 "\n", totalSize, pos, size);
423 
424 	status_t err = fBuffer->EvaluatePosition(pos, totalSize);
425 
426 	TRACE("BAdapterIO::_EvaluateWait: %s\n", strerror(err));
427 
428 	if (err != B_OK && err != B_WOULD_BLOCK)
429 		return err;
430 
431 	TRACE("BAdapterIO::_EvaluateWait: waiting for data\n");
432 
433 	return fBuffer->WaitForData(pos, size);
434 }
435 
436 
437 BInputAdapter::BInputAdapter(BAdapterIO* io)
438 	:
439 	fIO(io)
440 {
441 }
442 
443 
444 BInputAdapter::~BInputAdapter()
445 {
446 }
447 
448 
449 ssize_t
450 BInputAdapter::Write(const void* buffer, size_t size)
451 {
452 	return fIO->BackWrite(buffer, size);
453 }
454 
455 
456 // FBC
457 void BAdapterIO::_ReservedAdapterIO1() {}
458 void BAdapterIO::_ReservedAdapterIO2() {}
459 void BAdapterIO::_ReservedAdapterIO3() {}
460 void BAdapterIO::_ReservedAdapterIO4() {}
461 void BAdapterIO::_ReservedAdapterIO5() {}
462 
463 void BInputAdapter::_ReservedInputAdapter1() {}
464 void BInputAdapter::_ReservedInputAdapter2() {}
465