| OLD | NEW | 
|    1 // Copyright 2014 The Chromium Authors. All rights reserved. |    1 // Copyright 2014 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #ifndef MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ |    5 #ifndef MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ | 
|    6 #define MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ |    6 #define MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ | 
|    7  |    7  | 
|    8 #include <alsa/asoundlib.h> |    8 #include <alsa/asoundlib.h> | 
|    9 #include <stdint.h> |    9 #include <stdint.h> | 
 |   10  | 
|   10 #include <map> |   11 #include <map> | 
 |   12 #include <memory> | 
|   11 #include <utility> |   13 #include <utility> | 
|   12 #include <vector> |   14 #include <vector> | 
|   13  |   15  | 
|   14 #include "base/containers/hash_tables.h" |   16 #include "base/containers/hash_tables.h" | 
|   15 #include "base/gtest_prod_util.h" |   17 #include "base/gtest_prod_util.h" | 
|   16 #include "base/macros.h" |   18 #include "base/macros.h" | 
|   17 #include "base/memory/scoped_ptr.h" |  | 
|   18 #include "base/synchronization/lock.h" |   19 #include "base/synchronization/lock.h" | 
|   19 #include "base/threading/thread.h" |   20 #include "base/threading/thread.h" | 
|   20 #include "base/values.h" |   21 #include "base/values.h" | 
|   21 #include "device/udev_linux/scoped_udev.h" |   22 #include "device/udev_linux/scoped_udev.h" | 
|   22 #include "media/midi/midi_export.h" |   23 #include "media/midi/midi_export.h" | 
|   23 #include "media/midi/midi_manager.h" |   24 #include "media/midi/midi_manager.h" | 
|   24  |   25  | 
|   25 namespace base { |   26 namespace base { | 
|   26 class ThreadChecker; |   27 class ThreadChecker; | 
|   27 } |   28 } | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|   41                             uint32_t port_index, |   42                             uint32_t port_index, | 
|   42                             const std::vector<uint8_t>& data, |   43                             const std::vector<uint8_t>& data, | 
|   43                             double timestamp) override; |   44                             double timestamp) override; | 
|   44  |   45  | 
|   45  private: |   46  private: | 
|   46   friend class MidiManagerAlsaTest; |   47   friend class MidiManagerAlsaTest; | 
|   47   FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer); |   48   FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer); | 
|   48   FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ToMidiPortState); |   49   FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ToMidiPortState); | 
|   49  |   50  | 
|   50   class AlsaCard; |   51   class AlsaCard; | 
|   51   using AlsaCardMap = std::map<int, scoped_ptr<AlsaCard>>; |   52   using AlsaCardMap = std::map<int, std::unique_ptr<AlsaCard>>; | 
|   52  |   53  | 
|   53   class MidiPort { |   54   class MidiPort { | 
|   54    public: |   55    public: | 
|   55     enum class Type { kInput, kOutput }; |   56     enum class Type { kInput, kOutput }; | 
|   56  |   57  | 
|   57     // The Id class is used to keep the multiple strings separate |   58     // The Id class is used to keep the multiple strings separate | 
|   58     // but compare them all together for equality purposes. |   59     // but compare them all together for equality purposes. | 
|   59     // The individual strings that make up the Id can theoretically contain |   60     // The individual strings that make up the Id can theoretically contain | 
|   60     // arbitrary characters, so unfortunately there is no simple way to |   61     // arbitrary characters, so unfortunately there is no simple way to | 
|   61     // concatenate them into a single string. |   62     // concatenate them into a single string. | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|   92              int port_id, |   93              int port_id, | 
|   93              int midi_device, |   94              int midi_device, | 
|   94              const std::string& client_name, |   95              const std::string& client_name, | 
|   95              const std::string& port_name, |   96              const std::string& port_name, | 
|   96              const std::string& manufacturer, |   97              const std::string& manufacturer, | 
|   97              const std::string& version, |   98              const std::string& version, | 
|   98              Type type); |   99              Type type); | 
|   99     ~MidiPort(); |  100     ~MidiPort(); | 
|  100  |  101  | 
|  101     // Gets a Value representation of this object, suitable for serialization. |  102     // Gets a Value representation of this object, suitable for serialization. | 
|  102     scoped_ptr<base::Value> Value() const; |  103     std::unique_ptr<base::Value> Value() const; | 
|  103  |  104  | 
|  104     // Gets a string version of Value in JSON format. |  105     // Gets a string version of Value in JSON format. | 
|  105     std::string JSONValue() const; |  106     std::string JSONValue() const; | 
|  106  |  107  | 
|  107     // Gets an opaque identifier for this object, suitable for using as the id |  108     // Gets an opaque identifier for this object, suitable for using as the id | 
|  108     // field in MidiPort.id on the web. Note that this string does not store |  109     // field in MidiPort.id on the web. Note that this string does not store | 
|  109     // the full state. |  110     // the full state. | 
|  110     std::string OpaqueKey() const; |  111     std::string OpaqueKey() const; | 
|  111  |  112  | 
|  112     // Checks for equality for connected ports. |  113     // Checks for equality for connected ports. | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  176     uint32_t web_port_index_ = 0; |  177     uint32_t web_port_index_ = 0; | 
|  177  |  178  | 
|  178     // Port is present in the ALSA system. |  179     // Port is present in the ALSA system. | 
|  179     bool connected_ = true; |  180     bool connected_ = true; | 
|  180  |  181  | 
|  181     DISALLOW_COPY_AND_ASSIGN(MidiPort); |  182     DISALLOW_COPY_AND_ASSIGN(MidiPort); | 
|  182   }; |  183   }; | 
|  183  |  184  | 
|  184   class MidiPortStateBase { |  185   class MidiPortStateBase { | 
|  185    public: |  186    public: | 
|  186     typedef std::vector<scoped_ptr<MidiPort>>::iterator iterator; |  187     typedef std::vector<std::unique_ptr<MidiPort>>::iterator iterator; | 
|  187  |  188  | 
|  188     virtual ~MidiPortStateBase(); |  189     virtual ~MidiPortStateBase(); | 
|  189  |  190  | 
|  190     // Given a port, finds a port in the internal store. |  191     // Given a port, finds a port in the internal store. | 
|  191     iterator Find(const MidiPort& port); |  192     iterator Find(const MidiPort& port); | 
|  192  |  193  | 
|  193     // Given a port, finds a connected port, using exact matching. |  194     // Given a port, finds a connected port, using exact matching. | 
|  194     iterator FindConnected(const MidiPort& port); |  195     iterator FindConnected(const MidiPort& port); | 
|  195  |  196  | 
|  196     // Given a port, finds a disconnected port, using heuristic matching. |  197     // Given a port, finds a disconnected port, using heuristic matching. | 
|  197     iterator FindDisconnected(const MidiPort& port); |  198     iterator FindDisconnected(const MidiPort& port); | 
|  198  |  199  | 
|  199     iterator begin() { return ports_.begin(); } |  200     iterator begin() { return ports_.begin(); } | 
|  200     iterator end() { return ports_.end(); } |  201     iterator end() { return ports_.end(); } | 
|  201  |  202  | 
|  202    protected: |  203    protected: | 
|  203     MidiPortStateBase(); |  204     MidiPortStateBase(); | 
|  204     iterator erase(iterator position) { return ports_.erase(position); } |  205     iterator erase(iterator position) { return ports_.erase(position); } | 
|  205     void push_back(scoped_ptr<MidiPort> port) { |  206     void push_back(std::unique_ptr<MidiPort> port) { | 
|  206       ports_.push_back(std::move(port)); |  207       ports_.push_back(std::move(port)); | 
|  207     } |  208     } | 
|  208  |  209  | 
|  209    private: |  210    private: | 
|  210     std::vector<scoped_ptr<MidiPort>> ports_; |  211     std::vector<std::unique_ptr<MidiPort>> ports_; | 
|  211  |  212  | 
|  212     DISALLOW_COPY_AND_ASSIGN(MidiPortStateBase); |  213     DISALLOW_COPY_AND_ASSIGN(MidiPortStateBase); | 
|  213   }; |  214   }; | 
|  214  |  215  | 
|  215   class TemporaryMidiPortState final : public MidiPortStateBase { |  216   class TemporaryMidiPortState final : public MidiPortStateBase { | 
|  216    public: |  217    public: | 
|  217     iterator erase(iterator position) { |  218     iterator erase(iterator position) { | 
|  218       return MidiPortStateBase::erase(position); |  219       return MidiPortStateBase::erase(position); | 
|  219     }; |  220     }; | 
|  220     void push_back(scoped_ptr<MidiPort> port) { |  221     void push_back(std::unique_ptr<MidiPort> port) { | 
|  221       MidiPortStateBase::push_back(std::move(port)); |  222       MidiPortStateBase::push_back(std::move(port)); | 
|  222     } |  223     } | 
|  223   }; |  224   }; | 
|  224  |  225  | 
|  225   class MidiPortState final : public MidiPortStateBase { |  226   class MidiPortState final : public MidiPortStateBase { | 
|  226    public: |  227    public: | 
|  227     MidiPortState(); |  228     MidiPortState(); | 
|  228  |  229  | 
|  229     // Inserts a port at the end. Returns web_port_index. |  230     // Inserts a port at the end. Returns web_port_index. | 
|  230     uint32_t push_back(scoped_ptr<MidiPort> port); |  231     uint32_t push_back(std::unique_ptr<MidiPort> port); | 
|  231  |  232  | 
|  232    private: |  233    private: | 
|  233     uint32_t num_input_ports_ = 0; |  234     uint32_t num_input_ports_ = 0; | 
|  234     uint32_t num_output_ports_ = 0; |  235     uint32_t num_output_ports_ = 0; | 
|  235   }; |  236   }; | 
|  236  |  237  | 
|  237   class AlsaSeqState { |  238   class AlsaSeqState { | 
|  238    public: |  239    public: | 
|  239     enum class PortDirection { kInput, kOutput, kDuplex }; |  240     enum class PortDirection { kInput, kOutput, kDuplex }; | 
|  240  |  241  | 
|  241     AlsaSeqState(); |  242     AlsaSeqState(); | 
|  242     ~AlsaSeqState(); |  243     ~AlsaSeqState(); | 
|  243  |  244  | 
|  244     void ClientStart(int client_id, |  245     void ClientStart(int client_id, | 
|  245                      const std::string& client_name, |  246                      const std::string& client_name, | 
|  246                      snd_seq_client_type_t type); |  247                      snd_seq_client_type_t type); | 
|  247     bool ClientStarted(int client_id); |  248     bool ClientStarted(int client_id); | 
|  248     void ClientExit(int client_id); |  249     void ClientExit(int client_id); | 
|  249     void PortStart(int client_id, |  250     void PortStart(int client_id, | 
|  250                    int port_id, |  251                    int port_id, | 
|  251                    const std::string& port_name, |  252                    const std::string& port_name, | 
|  252                    PortDirection direction, |  253                    PortDirection direction, | 
|  253                    bool midi); |  254                    bool midi); | 
|  254     void PortExit(int client_id, int port_id); |  255     void PortExit(int client_id, int port_id); | 
|  255     snd_seq_client_type_t ClientType(int client_id) const; |  256     snd_seq_client_type_t ClientType(int client_id) const; | 
|  256     scoped_ptr<TemporaryMidiPortState> ToMidiPortState( |  257     std::unique_ptr<TemporaryMidiPortState> ToMidiPortState( | 
|  257         const AlsaCardMap& alsa_cards); |  258         const AlsaCardMap& alsa_cards); | 
|  258  |  259  | 
|  259     int card_client_count() { return card_client_count_; } |  260     int card_client_count() { return card_client_count_; } | 
|  260  |  261  | 
|  261    private: |  262    private: | 
|  262     class Port { |  263     class Port { | 
|  263      public: |  264      public: | 
|  264       Port(const std::string& name, PortDirection direction, bool midi); |  265       Port(const std::string& name, PortDirection direction, bool midi); | 
|  265       ~Port(); |  266       ~Port(); | 
|  266  |  267  | 
|  267       std::string name() const { return name_; } |  268       std::string name() const { return name_; } | 
|  268       PortDirection direction() const { return direction_; } |  269       PortDirection direction() const { return direction_; } | 
|  269       // True if this port is a MIDI port, instead of another kind of ALSA port. |  270       // True if this port is a MIDI port, instead of another kind of ALSA port. | 
|  270       bool midi() const { return midi_; } |  271       bool midi() const { return midi_; } | 
|  271  |  272  | 
|  272      private: |  273      private: | 
|  273       const std::string name_; |  274       const std::string name_; | 
|  274       const PortDirection direction_; |  275       const PortDirection direction_; | 
|  275       const bool midi_; |  276       const bool midi_; | 
|  276  |  277  | 
|  277       DISALLOW_COPY_AND_ASSIGN(Port); |  278       DISALLOW_COPY_AND_ASSIGN(Port); | 
|  278     }; |  279     }; | 
|  279  |  280  | 
|  280     class Client { |  281     class Client { | 
|  281      public: |  282      public: | 
|  282       using PortMap = std::map<int, scoped_ptr<Port>>; |  283       using PortMap = std::map<int, std::unique_ptr<Port>>; | 
|  283  |  284  | 
|  284       Client(const std::string& name, snd_seq_client_type_t type); |  285       Client(const std::string& name, snd_seq_client_type_t type); | 
|  285       ~Client(); |  286       ~Client(); | 
|  286  |  287  | 
|  287       std::string name() const { return name_; } |  288       std::string name() const { return name_; } | 
|  288       snd_seq_client_type_t type() const { return type_; } |  289       snd_seq_client_type_t type() const { return type_; } | 
|  289       void AddPort(int addr, scoped_ptr<Port> port); |  290       void AddPort(int addr, std::unique_ptr<Port> port); | 
|  290       void RemovePort(int addr); |  291       void RemovePort(int addr); | 
|  291       PortMap::const_iterator begin() const; |  292       PortMap::const_iterator begin() const; | 
|  292       PortMap::const_iterator end() const; |  293       PortMap::const_iterator end() const; | 
|  293  |  294  | 
|  294      private: |  295      private: | 
|  295       const std::string name_; |  296       const std::string name_; | 
|  296       const snd_seq_client_type_t type_; |  297       const snd_seq_client_type_t type_; | 
|  297       PortMap ports_; |  298       PortMap ports_; | 
|  298  |  299  | 
|  299       DISALLOW_COPY_AND_ASSIGN(Client); |  300       DISALLOW_COPY_AND_ASSIGN(Client); | 
|  300     }; |  301     }; | 
|  301  |  302  | 
|  302     std::map<int, scoped_ptr<Client>> clients_; |  303     std::map<int, std::unique_ptr<Client>> clients_; | 
|  303  |  304  | 
|  304     // This is the current number of clients we know about that have |  305     // This is the current number of clients we know about that have | 
|  305     // cards. When this number matches alsa_card_midi_count_, we know |  306     // cards. When this number matches alsa_card_midi_count_, we know | 
|  306     // we are in sync between ALSA and udev. Until then, we cannot generate |  307     // we are in sync between ALSA and udev. Until then, we cannot generate | 
|  307     // MIDIConnectionEvents to web clients. |  308     // MIDIConnectionEvents to web clients. | 
|  308     int card_client_count_ = 0; |  309     int card_client_count_ = 0; | 
|  309  |  310  | 
|  310     DISALLOW_COPY_AND_ASSIGN(AlsaSeqState); |  311     DISALLOW_COPY_AND_ASSIGN(AlsaSeqState); | 
|  311   }; |  312   }; | 
|  312  |  313  | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  361   }; |  362   }; | 
|  362  |  363  | 
|  363   struct SndMidiEventDeleter { |  364   struct SndMidiEventDeleter { | 
|  364     void operator()(snd_midi_event_t* coder) const { |  365     void operator()(snd_midi_event_t* coder) const { | 
|  365       snd_midi_event_free(coder); |  366       snd_midi_event_free(coder); | 
|  366     }; |  367     }; | 
|  367   }; |  368   }; | 
|  368  |  369  | 
|  369   using SourceMap = base::hash_map<int, uint32_t>; |  370   using SourceMap = base::hash_map<int, uint32_t>; | 
|  370   using OutPortMap = base::hash_map<uint32_t, int>; |  371   using OutPortMap = base::hash_map<uint32_t, int>; | 
|  371   using ScopedSndSeqPtr = scoped_ptr<snd_seq_t, SndSeqDeleter>; |  372   using ScopedSndSeqPtr = std::unique_ptr<snd_seq_t, SndSeqDeleter>; | 
|  372   using ScopedSndMidiEventPtr = |  373   using ScopedSndMidiEventPtr = | 
|  373       scoped_ptr<snd_midi_event_t, SndMidiEventDeleter>; |  374       std::unique_ptr<snd_midi_event_t, SndMidiEventDeleter>; | 
|  374  |  375  | 
|  375   // An internal callback that runs on MidiSendThread. |  376   // An internal callback that runs on MidiSendThread. | 
|  376   void SendMidiData(uint32_t port_index, const std::vector<uint8_t>& data); |  377   void SendMidiData(uint32_t port_index, const std::vector<uint8_t>& data); | 
|  377  |  378  | 
|  378   void ScheduleEventLoop(); |  379   void ScheduleEventLoop(); | 
|  379   void EventLoop(); |  380   void EventLoop(); | 
|  380   void ProcessSingleEvent(snd_seq_event_t* event, double timestamp); |  381   void ProcessSingleEvent(snd_seq_event_t* event, double timestamp); | 
|  381   void ProcessClientStartEvent(int client_id); |  382   void ProcessClientStartEvent(int client_id); | 
|  382   void ProcessPortStartEvent(const snd_seq_addr_t& addr); |  383   void ProcessPortStartEvent(const snd_seq_addr_t& addr); | 
|  383   void ProcessClientExitEvent(const snd_seq_addr_t& addr); |  384   void ProcessClientExitEvent(const snd_seq_addr_t& addr); | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  424   bool event_thread_shutdown_ = false;  // guarded by shutdown_lock_ |  425   bool event_thread_shutdown_ = false;  // guarded by shutdown_lock_ | 
|  425  |  426  | 
|  426   // This lock is needed to ensure that members destroyed in Finalize |  427   // This lock is needed to ensure that members destroyed in Finalize | 
|  427   // will be visibly destroyed before the destructor is run in the |  428   // will be visibly destroyed before the destructor is run in the | 
|  428   // other thread. Otherwise, the same objects may have their destructors |  429   // other thread. Otherwise, the same objects may have their destructors | 
|  429   // run multiple times in different threads. |  430   // run multiple times in different threads. | 
|  430   base::Lock lazy_init_member_lock_;  // guards members below |  431   base::Lock lazy_init_member_lock_;  // guards members below | 
|  431  |  432  | 
|  432   // Members initialized in StartInitialization() are below. |  433   // Members initialized in StartInitialization() are below. | 
|  433   // Make sure to destroy these in Finalize()! |  434   // Make sure to destroy these in Finalize()! | 
|  434   scoped_ptr<base::ThreadChecker> initialization_thread_checker_; |  435   std::unique_ptr<base::ThreadChecker> initialization_thread_checker_; | 
|  435  |  436  | 
|  436   // ALSA seq handles and ids. |  437   // ALSA seq handles and ids. | 
|  437   ScopedSndSeqPtr in_client_; |  438   ScopedSndSeqPtr in_client_; | 
|  438   int in_client_id_; |  439   int in_client_id_; | 
|  439   ScopedSndSeqPtr out_client_; |  440   ScopedSndSeqPtr out_client_; | 
|  440   int out_client_id_; |  441   int out_client_id_; | 
|  441   int in_port_id_; |  442   int in_port_id_; | 
|  442  |  443  | 
|  443   // ALSA event -> MIDI coder. |  444   // ALSA event -> MIDI coder. | 
|  444   ScopedSndMidiEventPtr decoder_; |  445   ScopedSndMidiEventPtr decoder_; | 
|  445  |  446  | 
|  446   // udev, for querying hardware devices. |  447   // udev, for querying hardware devices. | 
|  447   device::ScopedUdevPtr udev_; |  448   device::ScopedUdevPtr udev_; | 
|  448   device::ScopedUdevMonitorPtr udev_monitor_; |  449   device::ScopedUdevMonitorPtr udev_monitor_; | 
|  449  |  450  | 
|  450   // Threads for sending and receiving. These are initialized in the |  451   // Threads for sending and receiving. These are initialized in the | 
|  451   // constructor, but are started at the end of StartInitialization. |  452   // constructor, but are started at the end of StartInitialization. | 
|  452   base::Thread event_thread_; |  453   base::Thread event_thread_; | 
|  453   base::Thread send_thread_; |  454   base::Thread send_thread_; | 
|  454  |  455  | 
|  455   DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa); |  456   DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa); | 
|  456 }; |  457 }; | 
|  457  |  458  | 
|  458 }  // namespace midi |  459 }  // namespace midi | 
|  459 }  // namespace media |  460 }  // namespace media | 
|  460  |  461  | 
|  461 #endif  // MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ |  462 #endif  // MEDIA_MIDI_MIDI_MANAGER_ALSA_H_ | 
| OLD | NEW |