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