comparison libao2/ao_alsa.c @ 17616:92431bc3d014

This patch removes mmap support because it doesn't have any benefit. Directly accessing the sample buffer makes sense only when the samples can be constructed in-place. When the samples are just copied from another buffer (as is the case with libao2 drivers), the code to copy those samples is just a reimplementation of snd_pcm_writei(), so we could as well use that function. Besides, the current mmap code does not work except in the most simple cases: it claims to support non-interleaved and complex sample formats, but treats them the same as interleaved formats and writes to the wrong memory location.
author cladisch
date Mon, 13 Feb 2006 11:15:25 +0000
parents 9972b744fd98
children adfab82139c0
comparison
equal deleted inserted replaced
17615:363d23eb55d3 17616:92431bc3d014
15 #include <errno.h> 15 #include <errno.h>
16 #include <sys/time.h> 16 #include <sys/time.h>
17 #include <stdlib.h> 17 #include <stdlib.h>
18 #include <math.h> 18 #include <math.h>
19 #include <string.h> 19 #include <string.h>
20 #include <sys/poll.h>
21 20
22 #include "config.h" 21 #include "config.h"
23 #include "subopt-helper.h" 22 #include "subopt-helper.h"
24 #include "mixer.h" 23 #include "mixer.h"
25 #include "mp_msg.h" 24 #include "mp_msg.h"
64 static size_t bits_per_sample, bytes_per_sample, bits_per_frame; 63 static size_t bits_per_sample, bytes_per_sample, bits_per_frame;
65 static size_t chunk_bytes; 64 static size_t chunk_bytes;
66 65
67 static int ao_mmap = 0; 66 static int ao_mmap = 0;
68 static int ao_noblock = 0; 67 static int ao_noblock = 0;
69 static int first = 1;
70 68
71 static int open_mode; 69 static int open_mode;
72 static int set_block_mode; 70 static int set_block_mode;
73 static int alsa_can_pause = 0; 71 static int alsa_can_pause = 0;
74 72
75 #define ALSA_DEVICE_SIZE 256 73 #define ALSA_DEVICE_SIZE 256
76 74
77 #undef BUFFERTIME 75 #undef BUFFERTIME
78 #define SET_CHUNKSIZE 76 #define SET_CHUNKSIZE
79 #undef USE_POLL
80 77
81 /* to set/get/query special features/parameters */ 78 /* to set/get/query special features/parameters */
82 static int control(int cmd, void *arg) 79 static int control(int cmd, void *arg)
83 { 80 {
84 switch(cmd) { 81 switch(cmd) {
234 231
235 static void print_help (void) 232 static void print_help (void)
236 { 233 {
237 mp_msg (MSGT_AO, MSGL_FATAL, 234 mp_msg (MSGT_AO, MSGL_FATAL,
238 "\n-ao alsa commandline help:\n" 235 "\n-ao alsa commandline help:\n"
239 "Example: mplayer -ao alsa:mmap:device=hw=0.3\n" 236 "Example: mplayer -ao alsa:device=hw=0.3\n"
240 " sets mmap-mode and first card fourth device\n" 237 " sets first card fourth hardware device\n"
241 "\nOptions:\n" 238 "\nOptions:\n"
242 " mmap\n"
243 " Set memory-mapped mode, experimental\n"
244 " noblock\n" 239 " noblock\n"
245 " Sets non-blocking mode\n" 240 " Sets non-blocking mode\n"
246 " device=<device-name>\n" 241 " device=<device-name>\n"
247 " Sets device (change , to . and : to =)\n"); 242 " Sets device (change , to . and : to =)\n");
248 } 243 }
407 device.len = strlen(device.str); 402 device.len = strlen(device.str);
408 if (subopt_parse(ao_subdevice, subopts) != 0) { 403 if (subopt_parse(ao_subdevice, subopts) != 0) {
409 print_help(); 404 print_help();
410 return 0; 405 return 0;
411 } 406 }
407 if (ao_mmap)
408 mp_msg(MSGT_AO,MSGL_WARN,"alsa-init: mmap option is obsolete and has no effect");
412 ao_noblock = !block; 409 ao_noblock = !block;
413 parse_device(alsa_device, device.str, device.len); 410 parse_device(alsa_device, device.str, device.len);
414 411
415 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: %d soundcard%s found, using: %s\n", cards+1,(cards >= 0) ? "" : "s", alsa_device); 412 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: %d soundcard%s found, using: %s\n", cards+1,(cards >= 0) ? "" : "s", alsa_device);
416 413
454 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n"); 451 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
455 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n"); 452 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
456 break; 453 break;
457 default: 454 default:
458 alsa_fragcount = 16; 455 alsa_fragcount = 16;
459 if (ao_mmap) 456 chunk_size = 1024;
460 chunk_size = 512;
461 else
462 chunk_size = 1024;
463 break; 457 break;
464 } 458 }
465 } 459 }
466 460
467 if (!alsa_handler) { 461 if (!alsa_handler) {
498 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get initial parameters: %s\n", 492 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get initial parameters: %s\n",
499 snd_strerror(err)); 493 snd_strerror(err));
500 return(0); 494 return(0);
501 } 495 }
502 496
503 if (ao_mmap) { 497 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
504 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); 498 SND_PCM_ACCESS_RW_INTERLEAVED);
505 snd_pcm_access_mask_none(mask);
506 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
507 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
508 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
509 err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask);
510 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: mmap set\n");
511 } else {
512 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
513 SND_PCM_ACCESS_RW_INTERLEAVED);
514 }
515 if (err < 0) { 499 if (err < 0) {
516 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set access type: %s\n", 500 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set access type: %s\n",
517 snd_strerror(err)); 501 snd_strerror(err));
518 return (0); 502 return (0);
519 } 503 }
747 return; 731 return;
748 } 732 }
749 return; 733 return;
750 } 734 }
751 735
752 #ifdef USE_POLL
753 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count)
754 {
755 unsigned short revents;
756
757 while (1) {
758 poll(ufds, count, -1);
759 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents);
760 if (revents & POLLERR)
761 return -EIO;
762 if (revents & POLLOUT)
763 return 0;
764 }
765 }
766 #endif
767
768 #ifndef timersub 736 #ifndef timersub
769 #define timersub(a, b, result) \ 737 #define timersub(a, b, result) \
770 do { \ 738 do { \
771 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 739 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
772 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 740 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
807 775
808 return(1); /* ok, data should be accepted again */ 776 return(1); /* ok, data should be accepted again */
809 } 777 }
810 778
811 static int play_normal(void* data, int len); 779 static int play_normal(void* data, int len);
812 static int play_mmap(void* data, int len);
813 780
814 static int play(void* data, int len, int flags) 781 static int play(void* data, int len, int flags)
815 { 782 {
816 int result; 783 int result;
817 if (ao_mmap) 784 result = play_normal(data, len);
818 result = play_mmap(data, len);
819 else
820 result = play_normal(data, len);
821 785
822 return result; 786 return result;
823 } 787 }
824 788
825 /* 789 /*
884 if (res < 0) { 848 if (res < 0) {
885 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: write error %s", snd_strerror(res)); 849 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: write error %s", snd_strerror(res));
886 return 0; 850 return 0;
887 } 851 }
888 return len - len % bytes_per_sample; 852 return len - len % bytes_per_sample;
889 }
890
891 /* mmap-mode mainly based on descriptions by Joshua Haberman <joshua@haberman.com>
892 * 'An overview of the ALSA API' http://people.debian.org/~joshua/x66.html
893 * and some help by Paul Davis <pbd@op.net> */
894
895 static int play_mmap(void* data, int len)
896 {
897 snd_pcm_sframes_t commitres, frames_available;
898 snd_pcm_uframes_t frames_transmit, size, offset;
899 const snd_pcm_channel_area_t *area;
900 void *outbuffer;
901 int result;
902
903 #ifdef USE_POLL //seems not really be needed
904 struct pollfd *ufds;
905 int count;
906
907 count = snd_pcm_poll_descriptors_count (alsa_handler);
908 ufds = malloc(sizeof(struct pollfd) * count);
909 snd_pcm_poll_descriptors(alsa_handler, ufds, count);
910
911 //first wait_for_poll
912 if (err = (wait_for_poll(alsa_handler, ufds, count) < 0)) {
913 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
914 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
915 xrun("play");
916 }
917 }
918 #endif
919
920 outbuffer = alloca(ao_data.buffersize);
921
922 //don't trust get_space() ;)
923 frames_available = snd_pcm_avail_update(alsa_handler) * bytes_per_sample;
924 if (frames_available < 0)
925 xrun("play");
926
927 if (frames_available < 4) {
928 if (first) {
929 first = 0;
930 snd_pcm_start(alsa_handler);
931 }
932 else { //FIXME should break and return 0?
933 snd_pcm_wait(alsa_handler, -1);
934 first = 1;
935 }
936 }
937
938 /* len is simply the available bufferspace got by get_space()
939 * but real avail_buffer in frames is ab/bytes_per_sample */
940 size = len / bytes_per_sample;
941
942 //mp_msg(MSGT_AO,MSGL_V,"len: %i size %i, f_avail %i, bps %i ...\n", len, size, frames_available, bytes_per_sample);
943
944 frames_transmit = size;
945
946 /* prepare areas and set sw-pointers
947 * frames_transmit returns the real available buffer-size
948 * sometimes != frames_available cause of ringbuffer 'emulation' */
949 snd_pcm_mmap_begin(alsa_handler, &area, &offset, &frames_transmit);
950
951 /* this is specific to interleaved streams (or non-interleaved
952 * streams with only one channel) */
953 outbuffer = ((char *) area->addr + (area->first + area->step * offset) / 8); //8
954
955 //write data
956 memcpy(outbuffer, data, (frames_transmit * bytes_per_sample));
957
958 commitres = snd_pcm_mmap_commit(alsa_handler, offset, frames_transmit);
959
960 if (commitres < 0 || commitres != frames_transmit) {
961 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
962 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
963 xrun("play");
964 }
965 }
966
967 //mp_msg(MSGT_AO,MSGL_V,"mmap ft: %i, cres: %i\n", frames_transmit, commitres);
968
969 /* err = snd_pcm_area_copy(&area, offset, &data, offset, len, alsa_format); */
970 /* if (err < 0) { */
971 /* mp_msg(MSGT_AO,MSGL_ERR,"area-copy-error\n"); */
972 /* return 0; */
973 /* } */
974
975
976 //calculate written frames!
977 result = commitres * bytes_per_sample;
978
979
980 /* if (verbose) { */
981 /* if (len == result) */
982 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i ...\n", result, frames_transmit); */
983 /* else */
984 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i, result != len ...\n", result, frames_transmit); */
985 /* } */
986
987 //mplayer doesn't like -result
988 if (result < 0)
989 result = 0;
990
991 #ifdef USE_POLL
992 free(ufds);
993 #endif
994
995 return result;
996 } 853 }
997 854
998 /* how many byes are free in the buffer */ 855 /* how many byes are free in the buffer */
999 static int get_space(void) 856 static int get_space(void)
1000 { 857 {