Home | History | Annotate | Download | only in midi
      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 
     14 MidiManager::MidiManager()
     15     : initialized_(false),
     16       result_(MIDI_NOT_SUPPORTED) {
     17 }
     18 
     19 MidiManager::~MidiManager() {
     20 }
     21 
     22 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
     23     !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
     24 MidiManager* MidiManager::Create() {
     25   return new MidiManager;
     26 }
     27 #endif
     28 
     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 
     81 void MidiManager::EndSession(MidiManagerClient* client) {
     82   base::AutoLock auto_lock(lock_);
     83   clients_.erase(client);
     84   pending_clients_.erase(client);
     85 }
     86 
     87 void MidiManager::DispatchSendMidiData(MidiManagerClient* client,
     88                                        uint32 port_index,
     89                                        const std::vector<uint8>& data,
     90                                        double timestamp) {
     91   NOTREACHED();
     92 }
     93 
     94 void MidiManager::StartInitialization() {
     95   CompleteInitialization(MIDI_NOT_SUPPORTED);
     96 }
     97 
     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 
    109 void MidiManager::AddInputPort(const MidiPortInfo& info) {
    110   input_ports_.push_back(info);
    111 }
    112 
    113 void MidiManager::AddOutputPort(const MidiPortInfo& info) {
    114   output_ports_.push_back(info);
    115 }
    116 
    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 
    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