midi_service.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/midi/midi_service.h"
  5. #include "base/feature_list.h"
  6. #include "base/strings/stringprintf.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. #include "build/build_config.h"
  9. #include "media/midi/midi_manager.h"
  10. #include "media/midi/midi_switches.h"
  11. #include "media/midi/task_service.h"
  12. namespace midi {
  13. std::unique_ptr<MidiManager> MidiService::ManagerFactory::Create(
  14. MidiService* service) {
  15. return std::unique_ptr<MidiManager>(MidiManager::Create(service));
  16. }
  17. // static
  18. base::TimeDelta MidiService::TimestampToTimeDeltaDelay(
  19. base::TimeTicks timestamp) {
  20. if (timestamp.is_null())
  21. return base::TimeDelta();
  22. return std::max(timestamp - base::TimeTicks::Now(), base::TimeDelta());
  23. }
  24. MidiService::MidiService() : MidiService(std::make_unique<ManagerFactory>()) {}
  25. MidiService::MidiService(std::unique_ptr<ManagerFactory> factory)
  26. : manager_factory_(std::move(factory)),
  27. task_service_(std::make_unique<TaskService>()) {}
  28. MidiService::~MidiService() {
  29. base::AutoLock lock(lock_);
  30. DCHECK(!manager_);
  31. base::AutoLock threads_lock(threads_lock_);
  32. threads_.clear();
  33. }
  34. void MidiService::Shutdown() {
  35. base::AutoLock lock(lock_);
  36. if (manager_) {
  37. manager_->EndAllSessions();
  38. DCHECK(manager_destructor_runner_);
  39. manager_destructor_runner_->DeleteSoon(FROM_HERE, std::move(manager_));
  40. manager_destructor_runner_ = nullptr;
  41. }
  42. }
  43. void MidiService::StartSession(MidiManagerClient* client) {
  44. base::AutoLock lock(lock_);
  45. if (!manager_) {
  46. manager_ = manager_factory_->Create(this);
  47. DCHECK(!manager_destructor_runner_);
  48. manager_destructor_runner_ = base::ThreadTaskRunnerHandle::Get();
  49. }
  50. manager_->StartSession(client);
  51. }
  52. bool MidiService::EndSession(MidiManagerClient* client) {
  53. base::AutoLock lock(lock_);
  54. // |client| does not seem to be valid.
  55. if (!manager_ || !manager_->EndSession(client))
  56. return false;
  57. // Do not destruct MidiManager on macOS to avoid a Core MIDI issue that
  58. // MIDIClientCreate starts failing with the OSStatus -50 after repeated calls
  59. // of MIDIClientDispose. It rarely happens, but once it starts, it will never
  60. // get back to be sane. See https://crbug.com/718140.
  61. #if !BUILDFLAG(IS_MAC)
  62. if (!manager_->HasOpenSession()) {
  63. // MidiManager for each platform should be able to shutdown correctly even
  64. // if following destruction happens in the middle of StartInitialization().
  65. manager_.reset();
  66. DCHECK(manager_destructor_runner_);
  67. DCHECK(manager_destructor_runner_->BelongsToCurrentThread());
  68. manager_destructor_runner_ = nullptr;
  69. }
  70. #endif
  71. return true;
  72. }
  73. void MidiService::DispatchSendMidiData(MidiManagerClient* client,
  74. uint32_t port_index,
  75. const std::vector<uint8_t>& data,
  76. base::TimeTicks timestamp) {
  77. base::AutoLock lock(lock_);
  78. // MidiService needs to consider invalid DispatchSendMidiData calls without
  79. // an open session that could be sent from a broken renderer.
  80. if (manager_)
  81. manager_->DispatchSendMidiData(client, port_index, data, timestamp);
  82. }
  83. scoped_refptr<base::SingleThreadTaskRunner> MidiService::GetTaskRunner(
  84. size_t runner_id) {
  85. base::AutoLock lock(threads_lock_);
  86. if (threads_.size() <= runner_id)
  87. threads_.resize(runner_id + 1);
  88. if (!threads_[runner_id]) {
  89. threads_[runner_id] = std::make_unique<base::Thread>(
  90. base::StringPrintf("MidiServiceThread(%zu)", runner_id));
  91. #if BUILDFLAG(IS_WIN)
  92. threads_[runner_id]->init_com_with_mta(true);
  93. #endif
  94. threads_[runner_id]->Start();
  95. }
  96. return threads_[runner_id]->task_runner();
  97. }
  98. } // namespace midi