1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/midi/midi_manager.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/bind.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/debug/trace_event.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/message_loop/message_loop.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace media {
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiManager::MidiManager()
15a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : initialized_(false),
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      result_(MIDI_NOT_SUPPORTED) {
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiManager::~MidiManager() {
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MidiManager* MidiManager::Create() {
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return new MidiManager;
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
29a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid MidiManager::StartSession(MidiManagerClient* client, int client_id) {
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool session_is_ready;
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool session_needs_initialization = false;
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool too_many_pending_clients_exist = false;
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  {
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::AutoLock auto_lock(lock_);
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    session_is_ready = initialized_;
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!session_is_ready) {
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // Do not accept a new request if the pending client list contains too
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // many clients.
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      too_many_pending_clients_exist =
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          pending_clients_.size() >= kMaxPendingClientCount;
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (!too_many_pending_clients_exist) {
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // Call StartInitialization() only for the first request.
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        session_needs_initialization = pending_clients_.empty();
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        pending_clients_.insert(std::make_pair(client, client_id));
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      }
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Lazily initialize the MIDI back-end.
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!session_is_ready) {
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (session_needs_initialization) {
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      TRACE_EVENT0("midi", "MidiManager::StartInitialization");
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      session_thread_runner_ =
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          base::MessageLoop::current()->message_loop_proxy();
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      StartInitialization();
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (too_many_pending_clients_exist) {
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // Return an error immediately if there are too many requests.
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      client->CompleteStartSession(client_id, MIDI_INITIALIZATION_ERROR);
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return;
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // CompleteInitialization() will be called asynchronously when platform
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // dependent initialization is finished.
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
67a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Platform dependent initialization was already finished for previously
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // initialized clients.
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  MidiResult result;
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  {
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    base::AutoLock auto_lock(lock_);
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (result_ == MIDI_OK)
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      clients_.insert(client);
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    result = result_;
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  client->CompleteStartSession(client_id, result);
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManager::EndSession(MidiManagerClient* client) {
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  clients_.erase(client);
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  pending_clients_.erase(client);
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManager::DispatchSendMidiData(MidiManagerClient* client,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       uint32 port_index,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const std::vector<uint8>& data,
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       double timestamp) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MidiManager::StartInitialization() {
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  CompleteInitialization(MIDI_NOT_SUPPORTED);
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MidiManager::CompleteInitialization(MidiResult result) {
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(session_thread_runner_.get());
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // It is safe to post a task to the IO thread from here because the IO thread
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // should have stopped if the MidiManager is going to be destructed.
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  session_thread_runner_->PostTask(
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      FROM_HERE,
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::Bind(&MidiManager::CompleteInitializationInternal,
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 base::Unretained(this),
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 result));
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManager::AddInputPort(const MidiPortInfo& info) {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  input_ports_.push_back(info);
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManager::AddOutputPort(const MidiPortInfo& info) {
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  output_ports_.push_back(info);
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManager::ReceiveMidiData(
118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    uint32 port_index,
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const uint8* data,
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    size_t length,
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    double timestamp) {
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (ClientList::iterator i = clients_.begin(); i != clients_.end(); ++i)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*i)->ReceiveMidiData(port_index, data, length, timestamp);
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MidiManager::CompleteInitializationInternal(MidiResult result) {
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  TRACE_EVENT0("midi", "MidiManager::CompleteInitialization");
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(clients_.empty());
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(!initialized_);
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  initialized_ = true;
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  result_ = result;
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (PendingClientMap::iterator it = pending_clients_.begin();
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       it != pending_clients_.end();
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       ++it) {
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (result_ == MIDI_OK)
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      clients_.insert(it->first);
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    it->first->CompleteStartSession(it->second, result_);
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  pending_clients_.clear();
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace media
148