#ifndef MEDIA_MIDI_MIDI_MANAGER_H_
#define MEDIA_MIDI_MIDI_MANAGER_H_
+#include <map>
#include <set>
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
+#include "base/time/time.h"
#include "media/base/media_export.h"
#include "media/midi/midi_port_info.h"
+#include "media/midi/midi_result.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
namespace media {
// for details.
class MEDIA_EXPORT MidiManagerClient {
public:
- virtual ~MidiManagerClient() {}
+ virtual ~MidiManagerClient() {}
+
+ // CompleteStartSession() is called when platform dependent preparation is
+ // finished.
+ virtual void CompleteStartSession(int client_id, MidiResult result) = 0;
// ReceiveMidiData() is called when MIDI data has been received from the
// MIDI system.
// Manages access to all MIDI hardware.
class MEDIA_EXPORT MidiManager {
public:
- static MidiManager* Create();
+ static const size_t kMaxPendingClientCount = 128;
MidiManager();
virtual ~MidiManager();
+ // The constructor and the destructor will be called on the CrBrowserMain
+ // thread.
+ static MidiManager* Create();
+
// A client calls StartSession() to receive and send MIDI data.
// If the session is ready to start, the MIDI system is lazily initialized
// and the client is registered to receive MIDI data.
- // Returns |true| if the session succeeds to start.
- bool StartSession(MidiManagerClient* client);
+ // CompleteStartSession() is called with MIDI_OK if the session is started.
+ // Otherwise CompleteStartSession() is called with proper MidiResult code.
+ // StartSession() and EndSession() can be called on the Chrome_IOThread.
+ // CompleteStartSession() will be invoked on the same Chrome_IOThread.
+ void StartSession(MidiManagerClient* client, int client_id);
- // A client calls ReleaseSession() to stop receiving MIDI data.
+ // A client calls EndSession() to stop receiving MIDI data.
void EndSession(MidiManagerClient* client);
// DispatchSendMidiData() is called when MIDI data should be sent to the MIDI
// input_ports() is a list of MIDI ports for receiving MIDI data.
// Each individual port in this list can be identified by its
// integer index into this list.
- const MidiPortInfoList& input_ports() { return input_ports_; }
+ const MidiPortInfoList& input_ports() const { return input_ports_; }
// output_ports() is a list of MIDI ports for sending MIDI data.
// Each individual port in this list can be identified by its
// integer index into this list.
- const MidiPortInfoList& output_ports() { return output_ports_; }
+ const MidiPortInfoList& output_ports() const { return output_ports_; }
protected:
- // Initializes the MIDI system, returning |true| on success.
- // The default implementation is for unsupported platforms.
- virtual bool Initialize();
+ friend class MidiManagerUsb;
+
+ // Initializes the platform dependent MIDI system. MidiManager class has a
+ // default implementation that synchronously calls CompleteInitialization()
+ // with MIDI_NOT_SUPPORTED on the caller thread. A derived class for a
+ // specific platform should override this method correctly.
+ // This method is called on Chrome_IOThread thread inside StartSession().
+ // Platform dependent initialization can be processed synchronously or
+ // asynchronously. When the initialization is completed,
+ // CompleteInitialization() should be called with |result|.
+ // |result| should be MIDI_OK on success, otherwise a proper MidiResult.
+ virtual void StartInitialization();
+
+ // Called from a platform dependent implementation of StartInitialization().
+ // It invokes CompleteInitializationInternal() on the thread that calls
+ // StartSession() and distributes |result| to MIDIManagerClient objects in
+ // |pending_clients_|.
+ void CompleteInitialization(MidiResult result);
void AddInputPort(const MidiPortInfo& info);
void AddOutputPort(const MidiPortInfo& info);
// Dispatches to all clients.
+ // TODO(toyoshim): Fix the mac implementation to use
+ // |ReceiveMidiData(..., base::TimeTicks)|.
void ReceiveMidiData(uint32 port_index,
const uint8* data,
size_t length,
double timestamp);
- bool initialized_;
+ void ReceiveMidiData(uint32 port_index,
+ const uint8* data,
+ size_t length,
+ base::TimeTicks time) {
+ ReceiveMidiData(port_index, data, length,
+ (time - base::TimeTicks()).InSecondsF());
+ }
+
+ size_t clients_size_for_testing() const { return clients_.size(); }
+ size_t pending_clients_size_for_testing() const {
+ return pending_clients_.size();
+ }
+
+ private:
+ void CompleteInitializationInternal(MidiResult result);
// Keeps track of all clients who wish to receive MIDI data.
typedef std::set<MidiManagerClient*> ClientList;
ClientList clients_;
- // Protects access to our clients.
- base::Lock clients_lock_;
+ // Keeps track of all clients who are waiting for CompleteStartSession().
+ typedef std::map<int, MidiManagerClient*> PendingClientMap;
+ PendingClientMap pending_clients_;
+
+ // Keeps a SingleThreadTaskRunner of the thread that calls StartSession in
+ // order to invoke CompleteStartSession() on the thread.
+ scoped_refptr<base::SingleThreadTaskRunner> session_thread_runner_;
+
+ // Keeps true if platform dependent initialization is already completed.
+ bool initialized_;
+
+ // Keeps the platform dependent initialization result if initialization is
+ // completed. Otherwise keeps MIDI_NOT_SUPPORTED.
+ MidiResult result_;
+
+ // Protects access to |clients_|, |pending_clients_|, |initialized_|, and
+ // |result_|.
+ base::Lock lock_;
MidiPortInfoList input_ports_;
MidiPortInfoList output_ports_;