mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Added PCM timer selection for seq sender...
This commit is contained in:
parent
227fe9d226
commit
452d7704e1
2 changed files with 115 additions and 10 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
check_PROGRAMS=control mixer switches pause pcm latency seq playmidi1 timer \
|
check_PROGRAMS=control mixer switches pause pcm latency seq \
|
||||||
loopback
|
playmidi1 timer loopback
|
||||||
|
|
||||||
control_LDADD=../src/libasound.la
|
control_LDADD=../src/libasound.la
|
||||||
mixer_LDADD=../src/libasound.la
|
mixer_LDADD=../src/libasound.la
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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
|
* 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;
|
int err;
|
||||||
snd_seq_event_t ev;
|
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));
|
bzero(&ev, sizeof(ev));
|
||||||
ev.source.queue = queue;
|
ev.source.queue = queue;
|
||||||
ev.source.client = client;
|
ev.source.client = client;
|
||||||
|
|
@ -18,6 +89,7 @@ void event_sender_start_timer(snd_seq_t *handle, int client, int queue)
|
||||||
ev.type = SND_SEQ_EVENT_START;
|
ev.type = SND_SEQ_EVENT_START;
|
||||||
if ((err = snd_seq_event_output(handle, &ev))<0)
|
if ((err = snd_seq_event_output(handle, &ev))<0)
|
||||||
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
|
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
|
||||||
|
/* ugly, but working */
|
||||||
while (snd_seq_flush_output(handle)>0)
|
while (snd_seq_flush_output(handle)>0)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
@ -74,10 +146,12 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
|
||||||
snd_seq_port_info_t port;
|
snd_seq_port_info_t port;
|
||||||
snd_seq_port_subscribe_t sub;
|
snd_seq_port_subscribe_t sub;
|
||||||
fd_set out, in;
|
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;
|
char *ptr;
|
||||||
|
snd_pcm_t *phandle = NULL;
|
||||||
|
char *pbuf = NULL;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc < 1) {
|
||||||
fprintf(stderr, "Invalid destonation...\n");
|
fprintf(stderr, "Invalid destonation...\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +169,6 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
|
||||||
event_sender_filter(handle);
|
event_sender_filter(handle);
|
||||||
if ((err = snd_seq_block_mode(handle, 0))<0)
|
if ((err = snd_seq_block_mode(handle, 0))<0)
|
||||||
fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
|
fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
|
||||||
event_sender_start_timer(handle, client, queue);
|
|
||||||
bzero(&port, sizeof(port));
|
bzero(&port, sizeof(port));
|
||||||
strcpy(port.name, "Output");
|
strcpy(port.name, "Output");
|
||||||
if ((err = snd_seq_create_port(handle, &port)) < 0) {
|
if ((err = snd_seq_create_port(handle, &port)) < 0) {
|
||||||
|
|
@ -114,6 +187,10 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
|
||||||
ptr = argv[max];
|
ptr = argv[max];
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
continue;
|
continue;
|
||||||
|
if (!strcmp(ptr, "pcm")) {
|
||||||
|
pcm_flag = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
|
if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
|
||||||
fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
|
fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
|
||||||
return;
|
return;
|
||||||
|
|
@ -127,22 +204,50 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Destonation client = %i, port = %i\n", sub.dest.client, sub.dest.port);
|
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;
|
first = 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
FD_ZERO(&out);
|
FD_ZERO(&out);
|
||||||
FD_ZERO(&in);
|
FD_ZERO(&in);
|
||||||
FD_SET(max = snd_seq_file_descriptor(handle), &out);
|
max = snd_seq_file_descriptor(handle);
|
||||||
FD_SET(max = snd_seq_file_descriptor(handle), &in);
|
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)
|
if (select(max + 1, &in, &out, NULL, NULL) < 0)
|
||||||
break;
|
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) {
|
if (first) {
|
||||||
send_event(handle, queue, client, port.port, &sub, &time);
|
send_event(handle, queue, client, port.port, &sub, &time);
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FD_ISSET(max, &in)) {
|
if (FD_ISSET(snd_seq_file_descriptor(handle), &in)) {
|
||||||
do {
|
do {
|
||||||
if ((err = snd_seq_event_input(handle, &ev))<0)
|
if ((err = snd_seq_event_input(handle, &ev))<0)
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue