blob: 25b1ec378d62b8ca8e114c346ce9aa7a5ef52545 [file] [log] [blame]
toyoshim14a32342016-12-14 22:18:29 -08001// 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
5#include "media/midi/midi_service.h"
6
toyoshimf4d61522017-02-10 02:03:32 -08007#include "base/feature_list.h"
toyoshimf4d61522017-02-10 02:03:32 -08008#include "base/strings/stringprintf.h"
Takashi Toyoshimab3ec89a2017-11-09 14:02:48 +00009#include "build/build_config.h"
toyoshim14a32342016-12-14 22:18:29 -080010#include "media/midi/midi_manager.h"
toyoshimf4d61522017-02-10 02:03:32 -080011#include "media/midi/midi_switches.h"
toyoshimccb8ff92017-06-13 05:31:46 -070012#include "media/midi/task_service.h"
toyoshim14a32342016-12-14 22:18:29 -080013
14namespace midi {
15
Takashi Toyoshimaa88997d2017-09-07 08:30:18 +000016std::unique_ptr<MidiManager> MidiService::ManagerFactory::Create(
17 MidiService* service) {
18 return std::unique_ptr<MidiManager>(MidiManager::Create(service));
toyoshimf4d61522017-02-10 02:03:32 -080019}
20
Takashi Toyoshimaafb27d52017-09-13 11:50:41 +000021// static
tzik925e2c62018-02-02 07:39:45 +000022base::TimeDelta MidiService::TimestampToTimeDeltaDelay(
23 base::TimeTicks timestamp) {
24 if (timestamp.is_null())
25 return base::TimeDelta();
26 return std::max(timestamp - base::TimeTicks::Now(), base::TimeDelta());
Takashi Toyoshimaafb27d52017-09-13 11:50:41 +000027}
28
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090029MidiService::MidiService() : MidiService(std::make_unique<ManagerFactory>()) {}
toyoshimf4d61522017-02-10 02:03:32 -080030
Takashi Toyoshimaa88997d2017-09-07 08:30:18 +000031MidiService::MidiService(std::unique_ptr<ManagerFactory> factory)
Takashi Toyoshimaa88997d2017-09-07 08:30:18 +000032 : manager_factory_(std::move(factory)),
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090033 task_service_(std::make_unique<TaskService>()) {}
toyoshim14a32342016-12-14 22:18:29 -080034
35MidiService::~MidiService() {
36 base::AutoLock lock(lock_);
Takashi Toyoshima5a6e6a32018-09-27 11:20:52 +000037 DCHECK(!manager_);
toyoshimf4d61522017-02-10 02:03:32 -080038 base::AutoLock threads_lock(threads_lock_);
39 threads_.clear();
toyoshim14a32342016-12-14 22:18:29 -080040}
41
42void MidiService::Shutdown() {
43 base::AutoLock lock(lock_);
Takashi Toyoshimaf563b612017-05-26 20:19:00 +090044 if (manager_) {
Adithya Srinivasanc262ed32018-12-26 06:20:53 +000045 manager_->EndAllSessions();
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090046 DCHECK(manager_destructor_runner_);
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090047 manager_destructor_runner_->DeleteSoon(FROM_HERE, std::move(manager_));
Takashi Toyoshimaf563b612017-05-26 20:19:00 +090048 manager_destructor_runner_ = nullptr;
49 }
toyoshim14a32342016-12-14 22:18:29 -080050}
51
52void MidiService::StartSession(MidiManagerClient* client) {
53 base::AutoLock lock(lock_);
Takashi Toyoshimaf563b612017-05-26 20:19:00 +090054 if (!manager_) {
Takashi Toyoshimaa88997d2017-09-07 08:30:18 +000055 manager_ = manager_factory_->Create(this);
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090056 DCHECK(!manager_destructor_runner_);
57 manager_destructor_runner_ = base::ThreadTaskRunnerHandle::Get();
toyoshimf4d61522017-02-10 02:03:32 -080058 }
toyoshim14a32342016-12-14 22:18:29 -080059 manager_->StartSession(client);
60}
61
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090062bool MidiService::EndSession(MidiManagerClient* client) {
toyoshim14a32342016-12-14 22:18:29 -080063 base::AutoLock lock(lock_);
Takashi Toyoshimaa15a2222017-08-18 12:58:48 +000064
Takashi Toyoshima150b4432017-08-21 12:08:09 +000065 // |client| does not seem to be valid.
66 if (!manager_ || !manager_->EndSession(client))
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090067 return false;
Takashi Toyoshimaf563b612017-05-26 20:19:00 +090068
Takashi Toyoshima9051b552017-11-27 10:00:16 +000069// Do not destruct MidiManager on macOS to avoid a Core MIDI issue that
70// MIDIClientCreate starts failing with the OSStatus -50 after repeated calls
71// of MIDIClientDispose. It rarely happens, but once it starts, it will never
72// get back to be sane. See https://crbug.com/718140.
Avi Drissman56d38b62020-07-29 19:29:27 +000073#if !defined(OS_MAC)
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090074 if (!manager_->HasOpenSession()) {
toyoshimf4d61522017-02-10 02:03:32 -080075 // MidiManager for each platform should be able to shutdown correctly even
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090076 // if following destruction happens in the middle of StartInitialization().
toyoshimf4d61522017-02-10 02:03:32 -080077 manager_.reset();
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090078 DCHECK(manager_destructor_runner_);
79 DCHECK(manager_destructor_runner_->BelongsToCurrentThread());
Takashi Toyoshimaf563b612017-05-26 20:19:00 +090080 manager_destructor_runner_ = nullptr;
toyoshimf4d61522017-02-10 02:03:32 -080081 }
Takashi Toyoshima9051b552017-11-27 10:00:16 +000082#endif
Takashi Toyoshimabc959ee2018-01-09 16:04:04 +090083 return true;
toyoshim14a32342016-12-14 22:18:29 -080084}
85
86void MidiService::DispatchSendMidiData(MidiManagerClient* client,
87 uint32_t port_index,
88 const std::vector<uint8_t>& data,
tzik925e2c62018-02-02 07:39:45 +000089 base::TimeTicks timestamp) {
toyoshim14a32342016-12-14 22:18:29 -080090 base::AutoLock lock(lock_);
Takashi Toyoshimaa15a2222017-08-18 12:58:48 +000091
92 // MidiService needs to consider invalid DispatchSendMidiData calls without
93 // an open session that could be sent from a broken renderer.
94 if (manager_)
95 manager_->DispatchSendMidiData(client, port_index, data, timestamp);
toyoshim14a32342016-12-14 22:18:29 -080096}
97
toyoshimf4d61522017-02-10 02:03:32 -080098scoped_refptr<base::SingleThreadTaskRunner> MidiService::GetTaskRunner(
99 size_t runner_id) {
100 base::AutoLock lock(threads_lock_);
101 if (threads_.size() <= runner_id)
102 threads_.resize(runner_id + 1);
Takashi Toyoshimaf563b612017-05-26 20:19:00 +0900103 if (!threads_[runner_id]) {
Takashi Toyoshimaa88997d2017-09-07 08:30:18 +0000104 threads_[runner_id] = std::make_unique<base::Thread>(
toyoshimf4d61522017-02-10 02:03:32 -0800105 base::StringPrintf("MidiServiceThread(%zu)", runner_id));
toyoshimd28b59c2017-02-20 11:07:37 -0800106#if defined(OS_WIN)
107 threads_[runner_id]->init_com_with_mta(true);
108#endif
toyoshimf4d61522017-02-10 02:03:32 -0800109 threads_[runner_id]->Start();
110 }
111 return threads_[runner_id]->task_runner();
112}
113
toyoshim14a32342016-12-14 22:18:29 -0800114} // namespace midi