Mercurial > mplayer.hg
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 { |