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