+/*
+ * PCM timer layer
+ */
+
+int pcard = 0;
+int pdevice = 0;
+int pfragment_size = 4096;
+
+void set_format(snd_pcm_t *phandle)
+{
+ int err;
+ snd_pcm_format_t format;
+
+ bzero(&format, sizeof(format));
+ format.format = SND_PCM_SFMT_S16_LE;
+ format.channels = 2;
+ format.rate = 44100;
+ if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {
+ fprintf(stderr, "Playback format error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+}
+
+void set_fragment(snd_pcm_t *phandle)
+{
+ int err;
+ snd_pcm_playback_params_t pparams;
+
+ bzero(&pparams, sizeof(pparams));
+ pparams.fragment_size = pfragment_size;
+ pparams.fragments_max = -1; /* maximum */
+ pparams.fragments_room = 1;
+ if ((err = snd_pcm_playback_params(phandle, &pparams)) < 0) {
+ fprintf(stderr, "Fragment setup error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+}
+
+void show_playback_status(snd_pcm_t *phandle)
+{
+ int err;
+ snd_pcm_playback_status_t pstatus;
+
+ if ((err = snd_pcm_playback_status(phandle, &pstatus)) < 0) {
+ fprintf(stderr, "Playback status error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ printf("Playback status\n");
+ printf(" Real rate : %u\n", pstatus.rate);
+ printf(" Fragments : %i\n", pstatus.fragments);
+ printf(" Fragment size : %i\n", pstatus.fragment_size);
+}
+
/*
* Simple event sender
*/
-void event_sender_start_timer(snd_seq_t *handle, int client, int queue)
+void event_sender_start_timer(snd_seq_t *handle, int client, int queue, snd_pcm_t *phandle)
{
int err;
snd_seq_event_t ev;
+ if (phandle) {
+ snd_pcm_playback_info_t pinfo;
+ snd_seq_queue_timer_t qtimer;
+
+ if ((err = snd_pcm_playback_info(phandle, &pinfo)) < 0) {
+ fprintf(stderr, "Playback info error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ bzero(&qtimer, sizeof(qtimer));
+ qtimer.type = SND_SEQ_TIMER_MASTER;
+ /* note: last bit from subdevices specifies playback */
+ /* or capture direction for the timer specification */
+ qtimer.number = SND_TIMER_PCM(pcard, pdevice, pinfo.subdevice << 1);
+ if ((err = snd_seq_set_queue_timer(handle, queue, &qtimer)) < 0) {
+ fprintf(stderr, "Sequencer PCM timer setup failed: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ }
bzero(&ev, sizeof(ev));
ev.source.queue = queue;
ev.source.client = client;
ev.type = SND_SEQ_EVENT_START;
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
+ /* ugly, but working */
while (snd_seq_flush_output(handle)>0)
sleep(1);
}
snd_seq_port_info_t port;
snd_seq_port_subscribe_t sub;
fd_set out, in;
- int client, queue, max, err, v1, v2, time = 0, first;
+ int client, queue, max, err, v1, v2, time = 0, first, pcm_flag = 0;
char *ptr;
+ snd_pcm_t *phandle = NULL;
+ char *pbuf = NULL;
- if (argc != 1) {
+ if (argc < 1) {
fprintf(stderr, "Invalid destonation...\n");
return;
}
event_sender_filter(handle);
if ((err = snd_seq_block_mode(handle, 0))<0)
fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
- event_sender_start_timer(handle, client, queue);
bzero(&port, sizeof(port));
strcpy(port.name, "Output");
if ((err = snd_seq_create_port(handle, &port)) < 0) {
ptr = argv[max];
if (!ptr)
continue;
+ if (!strcmp(ptr, "pcm")) {
+ pcm_flag = 1;
+ continue;
+ }
if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
return;
}
printf("Destonation client = %i, port = %i\n", sub.dest.client, sub.dest.port);
+
+ if (pcm_flag) {
+ if ((err = snd_pcm_open(&phandle, pcard, pdevice, SND_PCM_OPEN_PLAYBACK)) < 0) {
+ fprintf(stderr, "Playback open error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ set_format(phandle);
+ set_fragment(phandle);
+ show_playback_status(phandle);
+ pbuf = calloc(1, pfragment_size);
+ if (pbuf == NULL) {
+ fprintf(stderr, "No enough memory...\n");
+ exit(0);
+ }
+ }
+ event_sender_start_timer(handle, client, queue, phandle);
first = 1;
while (1) {
FD_ZERO(&out);
FD_ZERO(&in);
- FD_SET(max = snd_seq_file_descriptor(handle), &out);
- FD_SET(max = snd_seq_file_descriptor(handle), &in);
+ max = snd_seq_file_descriptor(handle);
+ FD_SET(snd_seq_file_descriptor(handle), &out);
+ FD_SET(snd_seq_file_descriptor(handle), &in);
+ if (phandle) {
+ if (snd_pcm_file_descriptor(phandle) > max)
+ max = snd_pcm_file_descriptor(phandle);
+ FD_SET(snd_pcm_file_descriptor(phandle), &out);
+ }
if (select(max + 1, &in, &out, NULL, NULL) < 0)
break;
- if (FD_ISSET(max, &out)) {
+ if (phandle && FD_ISSET(snd_pcm_file_descriptor(phandle), &out)) {
+ if (snd_pcm_write(phandle, pbuf, pfragment_size) != pfragment_size) {
+ fprintf(stderr, "Playback write error!!\n");
+ exit(0);
+ }
+ }
+ if (FD_ISSET(snd_seq_file_descriptor(handle), &out)) {
if (first) {
send_event(handle, queue, client, port.port, &sub, &time);
first = 0;
}
}
- if (FD_ISSET(max, &in)) {
+ if (FD_ISSET(snd_seq_file_descriptor(handle), &in)) {
do {
if ((err = snd_seq_event_input(handle, &ev))<0)
break;