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