Now, two ports are connected by subscription. Then how to send events?
The subscribed port doesn't have to know the exact sender address. Instead, there is a special address for subscribers, SND_SEQ_ADDRESS_SUBSCRIBERS (= 254). The sender must set this value as the destination client. Destination port is ignored.
The other values in source and destination addresses are identical with the normal event record. If the event is scheduled, proper queue and timestamp values must be set.
There is a convenient function to set the address in an event record. In order to set destination as subscribers,
void snd_seq_ev_set_subs(snd_seq_event_t *ev);
If we send an event at the scheduled time t (tick) on the queue Q, the sender must set both schedule queue and time in the event record. The program appears like this:
void schedule_event(snd_seq_t *seq) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, my_port); snd_seq_ev_set_subs(&ev); snd_seq_ev_schedule_tick(&ev, Q, 0, t); ... // set event type, data, so on.. snd_seq_event_output(seq, &ev); ... snd_seq_flush_output(seq); // if necessary }Of course, you can use realtime stamp, too.
If the event is sent immediately without enqueued, the sender doesn't take care of queue and timestamp. As well as the case above, there is a function to set the direct delivery.
void snd_seq_ev_set_direct(snd_seq_event_t *ev);The program can be more simplified as follows:
void direct_delivery(snd_seq_t *seq) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, port); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); ... // set event type, data, so on.. snd_seq_output_event(seq, &ev); snd_seq_flush_output(seq); }You should flush event soon after output event. Otherwise, the event is enqueued on output queue of ALSA library (not in the kernel!), and will be never processed until this queue becomes full.
A typical filter program, which receives an event and sends it immediately after some modification, will appear as following:
void event_filter(snd_seq_t *seq, snd_seq_event_t *ev) { snd_seq_event_t *ev; while (snd_seq_event_input(seq, &ev) >= 0) { //.. modify input event .. snd_seq_ev_set_source(ev, my_port); snd_seq_ev_set_subs(ev); snd_seq_ev_set_direct(ev); snd_seq_event_output(seq, &ev); snd_seq_flush_output(seq); snd_seq_free_event(ev); } }