Mercurial > audlegacy-plugins
comparison src/alsa/audio.c @ 2760:35ac6cb80680
Use glib types.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 02 Jul 2008 08:03:42 +0300 |
parents | e99d3e8653df |
children | 58c63fbbd3ce |
comparison
equal
deleted
inserted
replaced
2759:fd550b4fc79f | 2760:35ac6cb80680 |
---|---|
44 /* Number of bytes that we have sent to the sound card */ | 44 /* Number of bytes that we have sent to the sound card */ |
45 static guint64 alsa_hw_written; | 45 static guint64 alsa_hw_written; |
46 static guint64 output_time_offset; | 46 static guint64 output_time_offset; |
47 | 47 |
48 /* device buffer/period sizes in bytes */ | 48 /* device buffer/period sizes in bytes */ |
49 static int hw_buffer_size, hw_period_size; /* in output bytes */ | 49 static gint hw_buffer_size, hw_period_size; /* in output bytes */ |
50 static int hw_buffer_size_in, hw_period_size_in; /* in input bytes */ | 50 static gint hw_buffer_size_in, hw_period_size_in; /* in input bytes */ |
51 | 51 |
52 /* Set/Get volume */ | 52 /* Set/Get volume */ |
53 static snd_mixer_elem_t *pcm_element; | 53 static snd_mixer_elem_t *pcm_element; |
54 static snd_mixer_t *mixer; | 54 static snd_mixer_t *mixer; |
55 | 55 |
58 | 58 |
59 static gboolean alsa_can_pause; | 59 static gboolean alsa_can_pause; |
60 | 60 |
61 /* for audio thread */ | 61 /* for audio thread */ |
62 static GThread *audio_thread; /* audio loop thread */ | 62 static GThread *audio_thread; /* audio loop thread */ |
63 static int thread_buffer_size; /* size of intermediate buffer in bytes */ | 63 static gint thread_buffer_size; /* size of intermediate buffer in bytes */ |
64 static char *thread_buffer; /* audio intermediate buffer */ | 64 static gchar *thread_buffer; /* audio intermediate buffer */ |
65 static int rd_index, wr_index; /* current read/write position in int-buffer */ | 65 static gint rd_index, wr_index; /* current read/write position in int-buffer */ |
66 static gboolean pause_request; /* pause status currently requested */ | 66 static gboolean pause_request; /* pause status currently requested */ |
67 static int flush_request; /* flush status (time) currently requested */ | 67 static gint flush_request; /* flush status (time) currently requested */ |
68 static int prebuffer_size; | 68 static gint prebuffer_size; |
69 GStaticMutex alsa_mutex = G_STATIC_MUTEX_INIT; | 69 GStaticMutex alsa_mutex = G_STATIC_MUTEX_INIT; |
70 | 70 |
71 struct snd_format { | 71 struct snd_format { |
72 unsigned int rate; | 72 guint rate; |
73 unsigned int channels; | 73 guint channels; |
74 snd_pcm_format_t format; | 74 snd_pcm_format_t format; |
75 AFormat xmms_format; | 75 AFormat xmms_format; |
76 int sample_bits; | 76 gint sample_bits; |
77 int bps; | 77 gint bps; |
78 }; | 78 }; |
79 | 79 |
80 static struct snd_format *inputf = NULL; | 80 static struct snd_format *inputf = NULL; |
81 static struct snd_format *outputf = NULL; | 81 static struct snd_format *outputf = NULL; |
82 | 82 |
83 static int alsa_setup(struct snd_format *f); | 83 static gint alsa_setup(struct snd_format *f); |
84 static void alsa_write_audio(char *data, int length); | 84 static void alsa_write_audio(gchar *data, gint length); |
85 static void alsa_cleanup_mixer(void); | 85 static void alsa_cleanup_mixer(void); |
86 static int get_thread_buffer_filled(void); | 86 static gint get_thread_buffer_filled(void); |
87 | 87 |
88 static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels); | 88 static struct snd_format * snd_format_from_xmms(AFormat fmt, gint rate, gint channels); |
89 | 89 |
90 static const struct { | 90 static const struct { |
91 AFormat xmms; | 91 AFormat xmms; |
92 snd_pcm_format_t alsa; | 92 snd_pcm_format_t alsa; |
93 } format_table[] = | 93 } format_table[] = |
113 {FMT_U8, SND_PCM_FORMAT_U8}, | 113 {FMT_U8, SND_PCM_FORMAT_U8}, |
114 {FMT_S8, SND_PCM_FORMAT_S8}, | 114 {FMT_S8, SND_PCM_FORMAT_S8}, |
115 }; | 115 }; |
116 | 116 |
117 | 117 |
118 static void debug(char *str, ...) G_GNUC_PRINTF(1, 2); | 118 static void debug(gchar *str, ...) G_GNUC_PRINTF(1, 2); |
119 | 119 |
120 static void debug(char *str, ...) | 120 static void debug(gchar *str, ...) |
121 { | 121 { |
122 va_list args; | 122 va_list args; |
123 | 123 |
124 if (alsa_cfg.debug) | 124 if (alsa_cfg.debug) |
125 { | 125 { |
138 !paused && | 138 !paused && |
139 !prebuffer && | 139 !prebuffer && |
140 get_thread_buffer_filled() > hw_period_size_in; | 140 get_thread_buffer_filled() > hw_period_size_in; |
141 } | 141 } |
142 | 142 |
143 static int | 143 static gint |
144 alsa_recovery(int err) | 144 alsa_recovery(gint err) |
145 { | 145 { |
146 int err2; | 146 gint err2; |
147 | 147 |
148 /* if debug mode is enabled, dump ALSA state to console */ | 148 /* if debug mode is enabled, dump ALSA state to console */ |
149 if (alsa_cfg.debug) | 149 if (alsa_cfg.debug) |
150 { | 150 { |
151 snd_pcm_status_t *alsa_status = NULL; | 151 snd_pcm_status_t *alsa_status = NULL; |
296 g_static_mutex_unlock(&alsa_mutex); | 296 g_static_mutex_unlock(&alsa_mutex); |
297 } | 297 } |
298 | 298 |
299 /* reopen ALSA PCM */ | 299 /* reopen ALSA PCM */ |
300 #if 0 | 300 #if 0 |
301 static int alsa_reopen(struct snd_format *f) | 301 static gint alsa_reopen(struct snd_format *f) |
302 { | 302 { |
303 /* remember the current position */ | 303 /* remember the current position */ |
304 output_time_offset += (alsa_hw_written * 1000) / outputf->bps; | 304 output_time_offset += (alsa_hw_written * 1000) / outputf->bps; |
305 alsa_hw_written = 0; | 305 alsa_hw_written = 0; |
306 | 306 |
309 return alsa_setup(f); | 309 return alsa_setup(f); |
310 } | 310 } |
311 #endif | 311 #endif |
312 | 312 |
313 /* do flush (drop) operation */ | 313 /* do flush (drop) operation */ |
314 static void alsa_do_flush(int time) | 314 static void alsa_do_flush(gint time) |
315 { | 315 { |
316 if (alsa_pcm) | 316 if (alsa_pcm) |
317 { | 317 { |
318 snd_pcm_drop(alsa_pcm); | 318 snd_pcm_drop(alsa_pcm); |
319 snd_pcm_prepare(alsa_pcm); | 319 snd_pcm_prepare(alsa_pcm); |
322 output_time_offset = time; | 322 output_time_offset = time; |
323 alsa_total_written = (guint64) time * inputf->bps / 1000; | 323 alsa_total_written = (guint64) time * inputf->bps / 1000; |
324 rd_index = wr_index = alsa_hw_written = 0; | 324 rd_index = wr_index = alsa_hw_written = 0; |
325 } | 325 } |
326 | 326 |
327 void alsa_flush(int time) | 327 void alsa_flush(gint time) |
328 { | 328 { |
329 flush_request = time; | 329 flush_request = time; |
330 while ((flush_request != -1) && (going)) | 330 while ((flush_request != -1) && (going)) |
331 g_usleep(10000); | 331 g_usleep(10000); |
332 } | 332 } |
333 | 333 |
334 static void parse_mixer_name(char *str, char **name, int *index) | 334 static void parse_mixer_name(gchar *str, gchar **name, gint *index) |
335 { | 335 { |
336 char *end; | 336 gchar *end; |
337 | 337 |
338 while (isspace(*str)) | 338 while (isspace(*str)) |
339 str++; | 339 str++; |
340 | 340 |
341 if ((end = strchr(str, ',')) != NULL) | 341 if ((end = strchr(str, ',')) != NULL) |
349 *name = g_strdup(str); | 349 *name = g_strdup(str); |
350 *index = 0; | 350 *index = 0; |
351 } | 351 } |
352 } | 352 } |
353 | 353 |
354 int alsa_get_mixer(snd_mixer_t **mixer, int card) | 354 gint alsa_get_mixer(snd_mixer_t **mixer, gint card) |
355 { | 355 { |
356 char *dev; | 356 gchar *dev; |
357 int err; | 357 gint err; |
358 | 358 |
359 debug("alsa_get_mixer"); | 359 debug("alsa_get_mixer"); |
360 | 360 |
361 if ((err = snd_mixer_open(mixer, 0)) < 0) | 361 if ((err = snd_mixer_open(mixer, 0)) < 0) |
362 { | 362 { |
391 | 391 |
392 return (*mixer != NULL); | 392 return (*mixer != NULL); |
393 } | 393 } |
394 | 394 |
395 | 395 |
396 static snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, char *name, int index) | 396 static snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, gchar *name, gint index) |
397 { | 397 { |
398 snd_mixer_selem_id_t *selem_id; | 398 snd_mixer_selem_id_t *selem_id; |
399 snd_mixer_elem_t* elem; | 399 snd_mixer_elem_t* elem; |
400 snd_mixer_selem_id_alloca(&selem_id); | 400 snd_mixer_selem_id_alloca(&selem_id); |
401 | 401 |
409 return elem; | 409 return elem; |
410 } | 410 } |
411 | 411 |
412 static int alsa_setup_mixer(void) | 412 static int alsa_setup_mixer(void) |
413 { | 413 { |
414 char *name; | 414 gchar *name; |
415 long int a, b; | 415 glong a, b; |
416 long alsa_min_vol, alsa_max_vol; | 416 glong alsa_min_vol, alsa_max_vol; |
417 int err, index; | 417 gint err, index; |
418 | 418 |
419 debug("alsa_setup_mixer"); | 419 debug("alsa_setup_mixer"); |
420 | 420 |
421 if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0) | 421 if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0) |
422 return err; | 422 return err; |
469 snd_mixer_close(mixer); | 469 snd_mixer_close(mixer); |
470 mixer = NULL; | 470 mixer = NULL; |
471 } | 471 } |
472 } | 472 } |
473 | 473 |
474 void alsa_get_volume(int *l, int *r) | 474 void alsa_get_volume(gint *l, gint *r) |
475 { | 475 { |
476 long ll = *l, lr = *r; | 476 glong ll = *l, lr = *r; |
477 | 477 |
478 if (mixer_start) | 478 if (mixer_start) |
479 { | 479 { |
480 alsa_setup_mixer(); | 480 alsa_setup_mixer(); |
481 mixer_start = FALSE; | 481 mixer_start = FALSE; |
495 *l = ll; | 495 *l = ll; |
496 *r = lr; | 496 *r = lr; |
497 } | 497 } |
498 | 498 |
499 | 499 |
500 void alsa_set_volume(int l, int r) | 500 void alsa_set_volume(gint l, gint r) |
501 { | 501 { |
502 if (!pcm_element) | 502 if (!pcm_element) |
503 return; | 503 return; |
504 | 504 |
505 if (snd_mixer_selem_is_playback_mono(pcm_element)) | 505 if (snd_mixer_selem_is_playback_mono(pcm_element)) |
539 if (wr_index >= rd_index) | 539 if (wr_index >= rd_index) |
540 return wr_index - rd_index; | 540 return wr_index - rd_index; |
541 return thread_buffer_size - (rd_index - wr_index); | 541 return thread_buffer_size - (rd_index - wr_index); |
542 } | 542 } |
543 | 543 |
544 int alsa_get_output_time(void) | 544 gint alsa_get_output_time(void) |
545 { | 545 { |
546 snd_pcm_sframes_t delay; | 546 snd_pcm_sframes_t delay; |
547 guint64 bytes = alsa_hw_written; | 547 guint64 bytes = alsa_hw_written; |
548 | 548 |
549 if (!going || alsa_pcm == NULL) | 549 if (!going || alsa_pcm == NULL) |
558 bytes -= d; | 558 bytes -= d; |
559 } | 559 } |
560 return output_time_offset + (bytes * 1000) / outputf->bps; | 560 return output_time_offset + (bytes * 1000) / outputf->bps; |
561 } | 561 } |
562 | 562 |
563 int alsa_get_written_time(void) | 563 gint alsa_get_written_time(void) |
564 { | 564 { |
565 if (!going) | 565 if (!going) |
566 return 0; | 566 return 0; |
567 return (alsa_total_written * 1000) / inputf->bps; | 567 return (alsa_total_written * 1000) / inputf->bps; |
568 } | 568 } |
579 | 579 |
580 alsa_write_audio(data, length); | 580 alsa_write_audio(data, length); |
581 } | 581 } |
582 | 582 |
583 /* write callback */ | 583 /* write callback */ |
584 void alsa_write(gpointer data, int length) | 584 void alsa_write(gpointer data, gint length) |
585 { | 585 { |
586 int cnt; | 586 gint cnt; |
587 char *src = (char *)data; | 587 gchar *src = (gchar *)data; |
588 | 588 |
589 remove_prebuffer = FALSE; | 589 remove_prebuffer = FALSE; |
590 | 590 |
591 alsa_total_written += length; | 591 alsa_total_written += length; |
592 while (length > 0) | 592 while (length > 0) |
600 src += cnt; | 600 src += cnt; |
601 } | 601 } |
602 } | 602 } |
603 | 603 |
604 /* transfer data to audio h/w via normal write */ | 604 /* transfer data to audio h/w via normal write */ |
605 static void alsa_write_audio(char *data, int length) | 605 static void alsa_write_audio(gchar *data, gint length) |
606 { | 606 { |
607 snd_pcm_sframes_t written_frames; | 607 snd_pcm_sframes_t written_frames; |
608 | 608 |
609 while (length > 0) | 609 while (length > 0) |
610 { | 610 { |
653 | 653 |
654 /* audio thread loop */ | 654 /* audio thread loop */ |
655 /* FIXME: proper lock? */ | 655 /* FIXME: proper lock? */ |
656 static void *alsa_loop(void *arg) | 656 static void *alsa_loop(void *arg) |
657 { | 657 { |
658 int npfds = snd_pcm_poll_descriptors_count(alsa_pcm); | 658 gint npfds = snd_pcm_poll_descriptors_count(alsa_pcm); |
659 int wr = 0; | 659 gint wr = 0; |
660 | 660 |
661 g_static_mutex_lock(&alsa_mutex); | 661 g_static_mutex_lock(&alsa_mutex); |
662 | 662 |
663 if (npfds <= 0) | 663 if (npfds <= 0) |
664 goto _error; | 664 goto _error; |
702 g_thread_exit(NULL); | 702 g_thread_exit(NULL); |
703 return(NULL); | 703 return(NULL); |
704 } | 704 } |
705 | 705 |
706 /* open callback */ | 706 /* open callback */ |
707 int alsa_open(AFormat fmt, int rate, int nch) | 707 gint alsa_open(AFormat fmt, gint rate, gint nch) |
708 { | 708 { |
709 debug("Opening device"); | 709 debug("Opening device"); |
710 if((inputf = snd_format_from_xmms(fmt, rate, nch)) == NULL) return 0; | 710 if((inputf = snd_format_from_xmms(fmt, rate, nch)) == NULL) return 0; |
711 | 711 |
712 if (alsa_cfg.debug) | 712 if (alsa_cfg.debug) |
749 | 749 |
750 audio_thread = g_thread_create((GThreadFunc)alsa_loop, NULL, TRUE, NULL); | 750 audio_thread = g_thread_create((GThreadFunc)alsa_loop, NULL, TRUE, NULL); |
751 return 1; | 751 return 1; |
752 } | 752 } |
753 | 753 |
754 static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels) | 754 static struct snd_format * snd_format_from_xmms(AFormat fmt, gint rate, gint channels) |
755 { | 755 { |
756 struct snd_format *f = g_malloc(sizeof(struct snd_format)); | 756 struct snd_format *f = g_malloc(sizeof(struct snd_format)); |
757 size_t i; | 757 size_t i; |
758 int found = 0; | 758 gint found = 0; |
759 | 759 |
760 f->xmms_format = fmt; | 760 f->xmms_format = fmt; |
761 f->format = SND_PCM_FORMAT_UNKNOWN; | 761 f->format = SND_PCM_FORMAT_UNKNOWN; |
762 | 762 |
763 for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) | 763 for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) |
788 f->bps = (rate * f->sample_bits * channels) >> 3; | 788 f->bps = (rate * f->sample_bits * channels) >> 3; |
789 | 789 |
790 return f; | 790 return f; |
791 } | 791 } |
792 | 792 |
793 static int alsa_setup(struct snd_format *f) | 793 static gint alsa_setup(struct snd_format *f) |
794 { | 794 { |
795 int err; | 795 gint err; |
796 snd_pcm_hw_params_t *hwparams = NULL; | 796 snd_pcm_hw_params_t *hwparams = NULL; |
797 snd_pcm_sw_params_t *swparams = NULL; | 797 snd_pcm_sw_params_t *swparams = NULL; |
798 unsigned int alsa_buffer_time, alsa_period_time; | 798 guint alsa_buffer_time, alsa_period_time; |
799 snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; | 799 snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; |
800 | 800 |
801 debug("alsa_setup"); | 801 debug("alsa_setup"); |
802 | 802 |
803 g_free(outputf); | 803 g_free(outputf); |