blob: ce217de45444caaaa27b3aea31941ee82389a372 [file] [log] [blame]
Prashant Malanifd1e2002017-08-09 13:22:59 -07001// Copyright 2017 The Chromium OS 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#ifndef MIDIS_SEQ_HANDLER_H_
6#define MIDIS_SEQ_HANDLER_H_
7
8#include <memory>
9
10#include <base/memory/weak_ptr.h>
11#include <brillo/message_loops/message_loop.h>
12
13#include "midis/device.h"
14#include "midis/device_tracker.h"
15#include "midis/seq_handler_interface.h"
16
17namespace midis {
18
19class DeviceTracker;
20
21// Class to handle all interactions with the ALSA sequencer interface.
22// NOTE: The term "input" refers to data received *from* the MIDI H/W and
23// external clients that are registered to the ALSA sequencer interfance. The
24// term "output" refers to data that a client of midis write *to* MIDI H/W and
25// external clients.
26class SeqHandler : public SeqHandlerInterface {
27 public:
28 using AddDeviceCallback = base::Callback<void(std::unique_ptr<Device>)>;
29 using RemoveDeviceCallback = base::Callback<void(uint32_t, uint32_t)>;
30 using HandleReceiveDataCallback =
31 base::Callback<void(uint32_t, uint32_t, uint32_t, const char*, size_t)>;
32 using IsDevicePresentCallback = base::Callback<bool(uint32_t, uint32_t)>;
33 using IsPortPresentCallback =
34 base::Callback<bool(uint32_t, uint32_t, uint32_t)>;
35
36 struct SeqDeleter {
37 void operator()(snd_seq_t* seq) const { snd_seq_close(seq); }
38 };
39
40 struct MidiEventDeleter {
41 void operator()(snd_midi_event_t* coder) const {
42 snd_midi_event_free(coder);
43 }
44 };
45
46 using ScopedMidiEventPtr =
47 std::unique_ptr<snd_midi_event_t, MidiEventDeleter>;
48 using ScopedSeqPtr = std::unique_ptr<snd_seq_t, SeqDeleter>;
49
50 SeqHandler(AddDeviceCallback add_device_cb,
51 RemoveDeviceCallback remove_device_cb,
52 HandleReceiveDataCallback handle_rx_data_cb,
53 IsDevicePresentCallback is_device_present_cb,
54 IsPortPresentCallback is_port_present_cb);
55
56 ~SeqHandler() override = default;
57
58 // Initializes the ALSA seq interface. Creates client handles for input and
59 // output, as well create an input port to receive messages (announce as
60 // well as MIDI data) from ALSA seq. Also starts off the file watcher which
61 // watches for events on the input port.
62 bool InitSeq() override;
63 void ProcessAlsaClientFd() override;
64
65 // Creates a Device object and runs the necessary callback to register that
66 // object with DeviceTracker, stored in |add_device_cb_|
67 void AddSeqDevice(uint32_t device_id) override;
68
69 // At present, we don't support hotplugging of individual ports in devices.
70 // so, we enumerate all the available ports in AddAlsaDevice().
71 // This function is here merely to handle MIDI events associated with any
72 // port being added or removed later (and to print an error message, since
73 // we don't support it yet)
74 void AddSeqPort(uint32_t device_id, uint32_t port_id) override;
75
76 // Runs the relevant callback, stored in |remove_device_cb_|, when a MIDI H/W
77 // device or external client is removed from the ALSA sequencer interface.
78 void RemoveSeqDevice(uint32_t device_id) override;
79
80 void RemoveSeqPort(uint32_t device_id, uint32_t port_id) override;
81
82 // Callback to run when starting an input port (establishes a subscription,
83 // and creates a relevant port on the server side, in necessary).
84 // Returns true on success, false otherwise.
85 bool SubscribeInPort(uint32_t device_id, uint32_t port_id) override;
86
87 // Callback to run when starting an input port (establishes a subscription,
88 // and creates a relevant port on the server side, in necessary).
89 // Returns created seq port id success, -1 otherwise.
90 int SubscribeOutPort(uint32_t device_id, uint32_t port_id) override;
91
92 // The following two functions undo the work of the Subscribe*Port() function,
93 // for input and output ports respectively.
94 void UnsubscribeInPort(uint32_t device_id, uint32_t port_id) override;
95 void UnsubscribeOutPort(int out_port_id) override;
96
97 // Callback to send MIDI data to the H/W. This callback is generally called by
98 // a Device handler which receives MIDI data from a client (e.g ARC++). The
99 // Device handler will in turn be called by a Client handler which is
100 // listening for data from it's client.
101 void SendMidiData(int out_port_id,
102 const uint8_t* buffer,
103 size_t buf_len) override;
104
105 // This function processes the MIDI data received from H/W or an external
106 // client, and invokes the callback |handle_rx_data_cb_| which handles the
107 // data accordingly.
108 void ProcessMidiEvent(snd_seq_event_t* event) override;
109
110 private:
111 std::unique_ptr<snd_seq_t, SeqDeleter> in_client_;
112 std::unique_ptr<snd_seq_t, SeqDeleter> out_client_;
113 std::unique_ptr<snd_midi_event_t, MidiEventDeleter> decoder_;
114 int in_client_id_;
115 int out_client_id_;
116 int in_port_id_;
117 std::unique_ptr<pollfd> pfd_;
118 brillo::MessageLoop::TaskId taskid_;
119
120 AddDeviceCallback add_device_cb_;
121 RemoveDeviceCallback remove_device_cb_;
122 HandleReceiveDataCallback handle_rx_data_cb_;
123 IsDevicePresentCallback is_device_present_cb_;
124 IsPortPresentCallback is_port_present_cb_;
125 base::WeakPtrFactory<SeqHandler> weak_factory_;
126
127 DISALLOW_COPY_AND_ASSIGN(SeqHandler);
128};
129
130} // namespace midis
131
132#endif // MIDIS_SEQ_HANDLER_H_