1 #pragma once 2 3 #include <assert.h> 4 5 #include <algorithm> 6 #include <chrono> 7 #include <iostream> 8 #include <map> 9 #include <thread> 10 using namespace std; 11 12 #include <scx/Conv.h> 13 #include <scx/FileHelper.h> 14 #include <scx/Mailbox.h> 15 using namespace scx; 16 17 #include <core/Plugin.h> 18 #include <plugin/IDecoder.h> 19 #include <plugin/IRenderer.h> 20 21 namespace mous { 22 struct UnitBuffer 23 { 24 uint32_t used; 25 uint32_t unitCount; 26 char data[]; 27 }; 28 29 struct DecoderPluginNode 30 { 31 const Plugin* agent; 32 IDecoder* decoder; 33 }; 34 35 enum : std::size_t 36 { 37 // mail contents 38 TYPE = 0, 39 DATA = 1, 40 FROM = 2, 41 42 // worker status 43 IDLE = 1u << 0, 44 RUNNING = 1u << 1, 45 46 // mail type 47 PROCEED = 1u << 2, 48 SUSPEND = 1u << 3, 49 DECODE = 1u << 4, 50 RENDER = 1u << 5, 51 QUIT = 1u << 6 52 }; 53 54 class Player::Impl 55 { 56 using Mailbox = scx::Mailbox<int, UnitBuffer*>; 57 using Mail = Mailbox::Mail; 58 59 public: Impl()60 Impl() 61 { 62 m_DecoderThread = std::thread([this]() { 63 int status = IDLE; 64 int quit = false; 65 66 while (!quit) { 67 auto mail = m_DecoderMailbox.Take(); 68 69 const int opcode = status | std::get<TYPE>(mail); 70 71 switch (opcode) { 72 case IDLE | QUIT: 73 case RUNNING | QUIT: { 74 quit = true; 75 } break; 76 77 case IDLE | PROCEED: { 78 status = RUNNING; 79 } break; 80 81 case IDLE | DECODE: { 82 std::get<TYPE>(mail) = 0; 83 m_BufferMailbox.PushBack(std::move(mail)); 84 } break; 85 86 case IDLE | SUSPEND: 87 case RUNNING | SUSPEND: { 88 status = IDLE; 89 } break; 90 91 case RUNNING | DECODE: { 92 auto& buf = std::get<DATA>(mail); 93 94 if (m_DecoderIndex < m_UnitEnd) { 95 m_Decoder->DecodeUnit(buf->data, buf->used, buf->unitCount); 96 m_DecoderIndex += buf->unitCount; 97 98 std::get<TYPE>(mail) = RENDER; 99 m_RendererMailbox.PushBack(std::move(mail)); 100 101 if (m_DecoderIndex >= m_UnitEnd) { 102 status = IDLE; 103 } 104 } else { 105 std::get<TYPE>(mail) = 0; 106 m_BufferMailbox.PushBack(std::move(mail)); 107 } 108 } break; 109 110 default: { 111 // unexpected 112 } break; 113 } 114 } 115 }); 116 117 m_RendererThread = std::thread([this]() { 118 int status = IDLE; 119 int quit = false; 120 121 while (!quit) { 122 auto mail = m_RendererMailbox.Take(); 123 124 const int opcode = status | std::get<TYPE>(mail); 125 126 switch (opcode) { 127 case IDLE | QUIT: 128 case RUNNING | QUIT: { 129 quit = true; 130 } break; 131 132 case IDLE | PROCEED: { 133 status = RUNNING; 134 } break; 135 136 case IDLE | RENDER: { 137 std::get<TYPE>(mail) = 0; 138 m_BufferMailbox.PushBack(std::move(mail)); 139 } break; 140 141 case IDLE | SUSPEND: 142 case RUNNING | SUSPEND: { 143 status = IDLE; 144 } break; 145 146 case RUNNING | RENDER: { 147 auto& buf = std::get<DATA>(mail); 148 149 if (m_RendererIndex < m_UnitEnd) { 150 if (m_Renderer->Write(buf->data, buf->used) != ErrorCode::Ok) { 151 // avoid busy write 152 const int64_t delay = buf->unitCount / m_UnitPerMs * 1e6; 153 std::this_thread::sleep_for(std::chrono::nanoseconds(delay)); 154 } 155 m_RendererIndex += buf->unitCount; 156 157 std::get<TYPE>(mail) = DECODE; 158 m_DecoderMailbox.PushBack(std::move(mail)); 159 160 if (m_RendererIndex >= m_UnitEnd) { 161 status = IDLE; 162 std::thread([this]() { m_SigFinished(); }).detach(); 163 } 164 } else { 165 std::get<TYPE>(mail) = 0; 166 m_BufferMailbox.PushBack(std::move(mail)); 167 } 168 } break; 169 170 default: { 171 // unexpected 172 } break; 173 } 174 } 175 }); 176 } 177 ~Impl()178 ~Impl() 179 { 180 Close(); 181 182 m_DecoderMailbox.EmplaceFront(QUIT, nullptr, std::weak_ptr<Mailbox>()); 183 m_RendererMailbox.EmplaceFront(QUIT, nullptr, std::weak_ptr<Mailbox>()); 184 185 if (m_DecoderThread.joinable()) { 186 m_DecoderThread.join(); 187 } 188 if (m_RendererThread.joinable()) { 189 m_RendererThread.join(); 190 } 191 192 m_BufferMailbox.Clear(); 193 194 UnregisterAll(); 195 } 196 Status()197 PlayerStatus Status() const { return m_Status; } 198 RegisterDecoderPlugin(const Plugin * pAgent)199 void RegisterDecoderPlugin(const Plugin* pAgent) 200 { 201 if (pAgent->Type() == PluginType::Decoder) { 202 AddDecoderPlugin(pAgent); 203 } 204 } 205 RegisterDecoderPlugin(vector<const Plugin * > & agents)206 void RegisterDecoderPlugin(vector<const Plugin*>& agents) 207 { 208 for (const auto agent : agents) { 209 RegisterDecoderPlugin(agent); 210 } 211 } 212 RegisterRendererPlugin(const Plugin * pAgent)213 void RegisterRendererPlugin(const Plugin* pAgent) 214 { 215 if (pAgent->Type() == PluginType::Renderer) { 216 SetRendererPlugin(pAgent); 217 } 218 } 219 UnregisterPlugin(const Plugin * pAgent)220 void UnregisterPlugin(const Plugin* pAgent) 221 { 222 switch (pAgent->Type()) { 223 case PluginType::Decoder: 224 RemoveDecoderPlugin(pAgent); 225 break; 226 227 case PluginType::Renderer: 228 UnsetRendererPlugin(pAgent); 229 break; 230 231 default: 232 break; 233 } 234 } 235 UnregisterPlugin(vector<const Plugin * > & agents)236 void UnregisterPlugin(vector<const Plugin*>& agents) 237 { 238 for (const auto agent : agents) { 239 UnregisterPlugin(agent); 240 } 241 } 242 UnregisterAll()243 void UnregisterAll() 244 { 245 while (!m_DecoderPluginMap.empty()) { 246 auto iter = m_DecoderPluginMap.begin(); 247 RemoveDecoderPlugin(iter->second.agent); 248 } 249 250 UnsetRendererPlugin(m_RendererPlugin); 251 } 252 SupportedSuffixes()253 vector<string> SupportedSuffixes() const 254 { 255 vector<string> list; 256 list.reserve(m_DecoderPluginMap.size()); 257 for (const auto& entry : m_DecoderPluginMap) { 258 list.push_back(entry.first); 259 } 260 return list; 261 } 262 BufferCount()263 int BufferCount() const 264 { 265 return m_BufferCount; 266 } 267 SetBufferCount(int count)268 void SetBufferCount(int count) 269 { 270 m_BufferCount = count; 271 } 272 Volume()273 int Volume() const { return m_Renderer != nullptr ? m_Renderer->VolumeLevel() : -1; } 274 SetVolume(int level)275 void SetVolume(int level) 276 { 277 if (m_Renderer != nullptr) { 278 m_Renderer->SetVolumeLevel(level); 279 } 280 } 281 Open(const string & path)282 ErrorCode Open(const string& path) 283 { 284 string suffix = ToLower(FileHelper::FileSuffix(path)); 285 // cout << "Suffix:" << suffix << endl; 286 auto iter = m_DecoderPluginMap.find(suffix); 287 if (iter != m_DecoderPluginMap.end()) { 288 m_Decoder = iter->second.decoder; 289 } else { 290 return ErrorCode::PlayerNoDecoder; 291 } 292 293 if (m_Renderer == nullptr) { 294 return ErrorCode::PlayerNoRenderer; 295 } 296 297 ErrorCode err = m_Decoder->Open(path); 298 if (err != ErrorCode::Ok) { 299 // cout << "FATAL: failed to open!" << endl; 300 return err; 301 } else { 302 m_DecodeFile = path; 303 } 304 305 const uint32_t maxBytesPerUnit = m_Decoder->MaxBytesPerUnit(); 306 // cout << "unit buf size:" << maxBytesPerUnit << endl; 307 308 m_BufferMailbox.Clear(); 309 m_Buffer = std::make_unique<char[]>(m_BufferCount * (sizeof(UnitBuffer) + maxBytesPerUnit)); 310 for (size_t i = 0; i < m_BufferCount; ++i) { 311 auto ptr = m_Buffer.get() + (sizeof(UnitBuffer) + maxBytesPerUnit) * i; 312 UnitBuffer* unitBuffer = reinterpret_cast<UnitBuffer*>(ptr); 313 m_BufferMailbox.EmplaceBack(0, unitBuffer, std::weak_ptr<Mailbox>()); 314 } 315 316 m_UnitPerMs = (double)m_Decoder->UnitCount() / m_Decoder->Duration(); 317 318 int32_t channels = m_Decoder->Channels(); 319 int32_t samleRate = m_Decoder->SampleRate(); 320 int32_t bitsPerSamle = m_Decoder->BitsPerSample(); 321 // cout << "channels:" << channels << endl; 322 // cout << "samleRate:" << samleRate << endl; 323 // cout << "bitsPerSamle:" << bitsPerSamle << endl; 324 err = m_Renderer->Setup(channels, samleRate, bitsPerSamle); 325 if (err != ErrorCode::Ok) { 326 cout << "FATAL: failed to set renderer:" << static_cast<uint8_t>(err) << endl; 327 cout << " channels:" << channels << endl; 328 cout << " samleRate:" << samleRate << endl; 329 cout << " bitsPerSamle:" << bitsPerSamle << endl; 330 return err; 331 } 332 333 m_Status = PlayerStatus::Stopped; 334 335 return err; 336 } 337 Close()338 void Close() 339 { 340 if (m_Status == PlayerStatus::Closed) { 341 return; 342 } 343 344 Pause(); 345 346 m_Decoder->Close(); 347 m_Decoder = nullptr; 348 m_DecodeFile.clear(); 349 350 m_Status = PlayerStatus::Closed; 351 } 352 FileName()353 string FileName() const { return m_DecodeFile; } 354 Play()355 void Play() 356 { 357 uint64_t beg = 0; 358 uint64_t end = m_Decoder->UnitCount(); 359 PlayRange(beg, end); 360 } 361 Play(uint64_t msBegin,uint64_t msEnd)362 void Play(uint64_t msBegin, uint64_t msEnd) 363 { 364 const uint64_t total = m_Decoder->UnitCount(); 365 366 uint64_t beg = 0; 367 uint64_t end = 0; 368 369 beg = m_UnitPerMs * msBegin; 370 if (beg > total) { 371 beg = total; 372 } 373 374 if (msEnd != (uint64_t)-1) { 375 end = m_UnitPerMs * msEnd; 376 if (end > total) { 377 end = total; 378 } 379 } else { 380 end = total; 381 } 382 383 // cout << "begin:" << beg << endl; 384 // cout << "end:" << end << endl; 385 // cout << "total:" << total << endl; 386 387 PlayRange(beg, end); 388 } 389 PlayRange(uint64_t beg,uint64_t end)390 void PlayRange(uint64_t beg, uint64_t end) 391 { 392 m_UnitBeg = beg; 393 m_UnitEnd = end; 394 395 m_RendererIndex = m_UnitBeg; 396 m_RendererMailbox.EmplaceBack(PROCEED, nullptr, std::weak_ptr<Mailbox>()); 397 398 m_DecoderIndex = m_UnitBeg; 399 m_Decoder->SetUnitIndex(m_UnitBeg); 400 m_DecoderMailbox.EmplaceBack(PROCEED, nullptr, std::weak_ptr<Mailbox>()); 401 while (!m_BufferMailbox.Empty()) { 402 auto mail = m_BufferMailbox.Take(); 403 std::get<TYPE>(mail) = DECODE; 404 m_DecoderMailbox.PushBack(std::move(mail)); 405 } 406 407 m_Status = PlayerStatus::Playing; 408 } 409 Pause()410 void Pause() 411 { 412 if (m_Status == PlayerStatus::Paused) { 413 return; 414 } 415 416 m_DecoderMailbox.EmplaceFront(SUSPEND, nullptr, std::weak_ptr<Mailbox>()); 417 m_RendererMailbox.EmplaceFront(SUSPEND, nullptr, std::weak_ptr<Mailbox>()); 418 m_BufferMailbox.Wait(m_BufferCount); 419 420 m_Status = PlayerStatus::Paused; 421 } 422 Resume()423 void Resume() 424 { 425 m_RendererMailbox.EmplaceBack(PROCEED, nullptr, std::weak_ptr<Mailbox>()); 426 427 m_DecoderIndex = m_RendererIndex; 428 m_Decoder->SetUnitIndex(m_DecoderIndex); 429 m_DecoderMailbox.EmplaceBack(PROCEED, nullptr, std::weak_ptr<Mailbox>()); 430 while (!m_BufferMailbox.Empty()) { 431 auto mail = m_BufferMailbox.Take(); 432 std::get<TYPE>(mail) = DECODE; 433 m_DecoderMailbox.PushBack(std::move(mail)); 434 } 435 436 m_Status = PlayerStatus::Playing; 437 } 438 SeekTime(uint64_t msPos)439 void SeekTime(uint64_t msPos) 440 { 441 switch (m_Status) { 442 case PlayerStatus::Playing: 443 Pause(); 444 DoSeekTime(msPos); 445 Resume(); 446 break; 447 448 case PlayerStatus::Paused: 449 case PlayerStatus::Stopped: 450 DoSeekTime(msPos); 451 break; 452 453 default: 454 break; 455 } 456 } 457 SeekPercent(double percent)458 void SeekPercent(double percent) 459 { 460 uint64_t unit = m_UnitBeg + (m_UnitEnd - m_UnitBeg) * percent; 461 462 switch (m_Status) { 463 case PlayerStatus::Playing: 464 Pause(); 465 DoSeekUnit(unit); 466 Resume(); 467 break; 468 469 case PlayerStatus::Paused: 470 case PlayerStatus::Stopped: 471 DoSeekUnit(unit); 472 break; 473 474 default: 475 break; 476 } 477 } 478 DoSeekTime(uint64_t msPos)479 void DoSeekTime(uint64_t msPos) 480 { 481 uint64_t unitPos = std::min((uint64_t)(m_UnitPerMs * msPos), m_Decoder->UnitCount()); 482 DoSeekUnit(unitPos); 483 } 484 DoSeekUnit(uint64_t unit)485 void DoSeekUnit(uint64_t unit) 486 { 487 if (unit < m_UnitBeg) { 488 unit = m_UnitBeg; 489 } else if (unit > m_UnitEnd) { 490 unit = m_UnitEnd; 491 } 492 493 m_Decoder->SetUnitIndex(unit); 494 495 m_DecoderIndex = unit; 496 m_RendererIndex = unit; 497 } 498 PauseDecoder()499 void PauseDecoder() 500 { 501 /* 502 if (!m_PauseDecoder) { 503 m_PauseDecoder = true; 504 } 505 m_SemDecoderEnd.Wait(); 506 507 m_Decoder->Close(); 508 */ 509 } 510 ResumeDecoder()511 void ResumeDecoder() 512 { 513 /* 514 // cout << "data:" << m_UnitBuffers.DataCount() << endl; 515 // cout << "free:" << m_UnitBuffers.FreeCount() << endl; 516 517 m_Decoder->Open(m_DecodeFile); 518 m_Decoder->SetUnitIndex(m_DecoderIndex); 519 520 m_PauseDecoder = false; 521 m_SemWakeDecoder.Post(); 522 m_SemDecoderBegin.Wait(); 523 */ 524 } 525 BitRate()526 int32_t BitRate() const { return (m_Decoder != nullptr) ? m_Decoder->BitRate() : -1; } 527 SamleRate()528 int32_t SamleRate() const { return (m_Decoder != nullptr) ? m_Decoder->SampleRate() : -1; } 529 Duration()530 uint64_t Duration() const { return m_Decoder->Duration(); } 531 RangeBegin()532 uint64_t RangeBegin() const { return m_UnitBeg / m_UnitPerMs; } 533 RangeEnd()534 uint64_t RangeEnd() const { return m_UnitEnd / m_UnitPerMs; } 535 RangeDuration()536 uint64_t RangeDuration() const { return (m_UnitEnd - m_UnitBeg) / m_UnitPerMs; } 537 OffsetMs()538 uint64_t OffsetMs() const { return CurrentMs() - RangeBegin(); } 539 CurrentMs()540 uint64_t CurrentMs() const { return m_RendererIndex / m_UnitPerMs; } 541 AudioMode()542 enum AudioMode AudioMode() const { return (m_Decoder != nullptr) ? m_Decoder->AudioMode() : AudioMode::None; } 543 DecoderPluginOption()544 std::vector<PluginOption> DecoderPluginOption() const 545 { 546 std::vector<PluginOption> list; 547 548 list.reserve(m_DecoderPluginMap.size()); 549 550 for (const auto entry : m_DecoderPluginMap) { 551 auto node = entry.second; 552 list.emplace_back(node.agent->Type(), node.agent->Info(), node.decoder->Options()); 553 } 554 555 return list; 556 } 557 RendererPluginOption()558 PluginOption RendererPluginOption() const 559 { 560 if (m_RendererPlugin != nullptr && m_Renderer != nullptr) { 561 return { m_RendererPlugin->Type(), m_RendererPlugin->Info(), m_Renderer->Options() }; 562 } else { 563 return {}; 564 } 565 } 566 SigFinished()567 Signal<void(void)>* SigFinished() { return &m_SigFinished; } 568 569 private: AddDecoderPlugin(const Plugin * pAgent)570 void AddDecoderPlugin(const Plugin* pAgent) 571 { 572 // create Decoder & get suffix 573 IDecoder* pDecoder = (IDecoder*)pAgent->CreateObject(); 574 const vector<string>& list = pDecoder->FileSuffix(); 575 576 // try add 577 bool usedAtLeastOnce = false; 578 for (const string& item : list) { 579 const string& suffix = ToLower(item); 580 auto iter = m_DecoderPluginMap.find(suffix); 581 if (iter == m_DecoderPluginMap.end()) { 582 m_DecoderPluginMap.emplace(suffix, DecoderPluginNode{ pAgent, pDecoder }); 583 usedAtLeastOnce = true; 584 } 585 } 586 587 // clear if not used 588 if (!usedAtLeastOnce) { 589 pAgent->FreeObject(pDecoder); 590 } 591 } 592 RemoveDecoderPlugin(const Plugin * pAgent)593 void RemoveDecoderPlugin(const Plugin* pAgent) 594 { 595 // get suffix 596 IDecoder* pDecoder = (IDecoder*)pAgent->CreateObject(); 597 const vector<string>& list = pDecoder->FileSuffix(); 598 pAgent->FreeObject(pDecoder); 599 600 // find plugin 601 bool freedOnce = false; 602 for (const string& item : list) { 603 const string& suffix = ToLower(item); 604 auto iter = m_DecoderPluginMap.find(suffix); 605 if (iter != m_DecoderPluginMap.end()) { 606 const DecoderPluginNode& node = iter->second; 607 if (node.agent == pAgent) { 608 if (!freedOnce) { 609 if (node.decoder == m_Decoder) { 610 Close(); 611 } 612 pAgent->FreeObject(node.decoder); 613 freedOnce = true; 614 } 615 m_DecoderPluginMap.erase(iter); 616 } 617 } 618 } 619 } 620 SetRendererPlugin(const Plugin * pAgent)621 void SetRendererPlugin(const Plugin* pAgent) 622 { 623 if (pAgent == nullptr || m_RendererPlugin != nullptr) { 624 return; 625 } 626 627 m_RendererPlugin = pAgent; 628 m_Renderer = (IRenderer*)pAgent->CreateObject(); 629 m_Renderer->Open(); 630 } 631 UnsetRendererPlugin(const Plugin * pAgent)632 void UnsetRendererPlugin(const Plugin* pAgent) 633 { 634 if (pAgent != m_RendererPlugin || m_RendererPlugin == nullptr) { 635 return; 636 } 637 638 m_Renderer->Close(); 639 m_RendererPlugin->FreeObject(m_Renderer); 640 m_Renderer = nullptr; 641 m_RendererPlugin = nullptr; 642 } 643 644 private: 645 PlayerStatus m_Status = PlayerStatus::Closed; 646 647 std::string m_DecodeFile; 648 649 IDecoder* m_Decoder = nullptr; 650 IRenderer* m_Renderer = nullptr; 651 std::thread m_DecoderThread; 652 std::thread m_RendererThread; 653 Mailbox m_DecoderMailbox; 654 Mailbox m_RendererMailbox; 655 656 Mailbox m_BufferMailbox; 657 int m_BufferCount = 5; 658 std::unique_ptr<char[]> m_Buffer; 659 660 uint64_t m_UnitBeg = 0; 661 uint64_t m_UnitEnd = 0; 662 663 uint64_t m_DecoderIndex = 0; 664 uint64_t m_RendererIndex = 0; 665 666 double m_UnitPerMs = 0; 667 668 const Plugin* m_RendererPlugin = nullptr; 669 std::map<std::string, DecoderPluginNode> m_DecoderPluginMap; 670 671 scx::Signal<void(void)> m_SigFinished; 672 }; 673 } 674