• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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_manager.h"
6 
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 
12 namespace media {
13 
MidiManager()14 MidiManager::MidiManager()
15     : initialized_(false),
16       result_(MIDI_NOT_SUPPORTED) {
17 }
18 
~MidiManager()19 MidiManager::~MidiManager() {
20 }
21 
22 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
23     !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
Create()24 MidiManager* MidiManager::Create() {
25   return new MidiManager;
26 }
27 #endif
28 
StartSession(MidiManagerClient * client,int client_id)29 void MidiManager::StartSession(MidiManagerClient* client, int client_id) {
30   bool session_is_ready;
31   bool session_needs_initialization = false;
32   bool too_many_pending_clients_exist = false;
33 
34   {
35     base::AutoLock auto_lock(lock_);
36     session_is_ready = initialized_;
37     if (!session_is_ready) {
38       // Do not accept a new request if the pending client list contains too
39       // many clients.
40       too_many_pending_clients_exist =
41           pending_clients_.size() >= kMaxPendingClientCount;
42 
43       if (!too_many_pending_clients_exist) {
44         // Call StartInitialization() only for the first request.
45         session_needs_initialization = pending_clients_.empty();
46         pending_clients_.insert(std::make_pair(client, client_id));
47       }
48     }
49   }
50 
51   // Lazily initialize the MIDI back-end.
52   if (!session_is_ready) {
53     if (session_needs_initialization) {
54       TRACE_EVENT0("midi", "MidiManager::StartInitialization");
55       session_thread_runner_ =
56           base::MessageLoop::current()->message_loop_proxy();
57       StartInitialization();
58     }
59     if (too_many_pending_clients_exist) {
60       // Return an error immediately if there are too many requests.
61       client->CompleteStartSession(client_id, MIDI_INITIALIZATION_ERROR);
62       return;
63     }
64     // CompleteInitialization() will be called asynchronously when platform
65     // dependent initialization is finished.
66     return;
67   }
68 
69   // Platform dependent initialization was already finished for previously
70   // initialized clients.
71   MidiResult result;
72   {
73     base::AutoLock auto_lock(lock_);
74     if (result_ == MIDI_OK)
75       clients_.insert(client);
76     result = result_;
77   }
78   client->CompleteStartSession(client_id, result);
79 }
80 
EndSession(MidiManagerClient * client)81 void MidiManager::EndSession(MidiManagerClient* client) {
82   base::AutoLock auto_lock(lock_);
83   clients_.erase(client);
84   pending_clients_.erase(client);
85 }
86 
DispatchSendMidiData(MidiManagerClient * client,uint32 port_index,const std::vector<uint8> & data,double timestamp)87 void MidiManager::DispatchSendMidiData(MidiManagerClient* client,
88                                        uint32 port_index,
89                                        const std::vector<uint8>& data,
90                                        double timestamp) {
91   NOTREACHED();
92 }
93 
StartInitialization()94 void MidiManager::StartInitialization() {
95   CompleteInitialization(MIDI_NOT_SUPPORTED);
96 }
97 
CompleteInitialization(MidiResult result)98 void MidiManager::CompleteInitialization(MidiResult result) {
99   DCHECK(session_thread_runner_.get());
100   // It is safe to post a task to the IO thread from here because the IO thread
101   // should have stopped if the MidiManager is going to be destructed.
102   session_thread_runner_->PostTask(
103       FROM_HERE,
104       base::Bind(&MidiManager::CompleteInitializationInternal,
105                  base::Unretained(this),
106                  result));
107 }
108 
AddInputPort(const MidiPortInfo & info)109 void MidiManager::AddInputPort(const MidiPortInfo& info) {
110   input_ports_.push_back(info);
111 }
112 
AddOutputPort(const MidiPortInfo & info)113 void MidiManager::AddOutputPort(const MidiPortInfo& info) {
114   output_ports_.push_back(info);
115 }
116 
ReceiveMidiData(uint32 port_index,const uint8 * data,size_t length,double timestamp)117 void MidiManager::ReceiveMidiData(
118     uint32 port_index,
119     const uint8* data,
120     size_t length,
121     double timestamp) {
122   base::AutoLock auto_lock(lock_);
123 
124   for (ClientList::iterator i = clients_.begin(); i != clients_.end(); ++i)
125     (*i)->ReceiveMidiData(port_index, data, length, timestamp);
126 }
127 
CompleteInitializationInternal(MidiResult result)128 void MidiManager::CompleteInitializationInternal(MidiResult result) {
129   TRACE_EVENT0("midi", "MidiManager::CompleteInitialization");
130 
131   base::AutoLock auto_lock(lock_);
132   DCHECK(clients_.empty());
133   DCHECK(!initialized_);
134   initialized_ = true;
135   result_ = result;
136 
137   for (PendingClientMap::iterator it = pending_clients_.begin();
138        it != pending_clients_.end();
139        ++it) {
140     if (result_ == MIDI_OK)
141       clients_.insert(it->first);
142     it->first->CompleteStartSession(it->second, result_);
143   }
144   pending_clients_.clear();
145 }
146 
147 }  // namespace media
148