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 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 212 private: 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 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 251 BAdapterIO::BAdapterIO(const BAdapterIO &) 252 { 253 // copying not allowed... 254 } 255 256 257 BAdapterIO::~BAdapterIO() 258 { 259 CALLED(); 260 261 delete fInputAdapter; 262 delete fBuffer; 263 } 264 265 266 void 267 BAdapterIO::GetFlags(int32* flags) const 268 { 269 CALLED(); 270 271 *flags = fFlags; 272 } 273 274 275 ssize_t 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 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 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 336 BAdapterIO::Position() const 337 { 338 CALLED(); 339 340 return fBuffer->Position(); 341 } 342 343 344 status_t 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 359 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 373 BAdapterIO::Open() 374 { 375 CALLED(); 376 377 fOpened = true; 378 return B_OK; 379 } 380 381 382 bool 383 BAdapterIO::IsRunning() const 384 { 385 return fOpened; 386 } 387 388 389 void 390 BAdapterIO::SeekCompleted() 391 { 392 CALLED(); 393 release_sem(fSeekSem); 394 delete_sem(fSeekSem); 395 fSeekSem = -1; 396 } 397 398 399 status_t 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 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* 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 434 BAdapterIO::SeekRequested(off_t position) 435 { 436 CALLED(); 437 438 return B_ERROR; 439 } 440 441 442 ssize_t 443 BAdapterIO::BackWrite(const void* buffer, size_t size) 444 { 445 return fBuffer->BackWrite(buffer, size); 446 } 447 448 449 status_t 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 474 BInputAdapter::BInputAdapter(BAdapterIO* io) 475 : 476 fIO(io) 477 { 478 } 479 480 481 BInputAdapter::~BInputAdapter() 482 { 483 } 484 485 486 ssize_t 487 BInputAdapter::Write(const void* buffer, size_t size) 488 { 489 return fIO->BackWrite(buffer, size); 490 } 491 492 493 // FBC 494 void BAdapterIO::_ReservedAdapterIO1() {} 495 void BAdapterIO::_ReservedAdapterIO2() {} 496 void BAdapterIO::_ReservedAdapterIO3() {} 497 void BAdapterIO::_ReservedAdapterIO4() {} 498 void BAdapterIO::_ReservedAdapterIO5() {} 499 500 void BInputAdapter::_ReservedInputAdapter1() {} 501 void BInputAdapter::_ReservedInputAdapter2() {} 502