aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sound.c401
1 files changed, 392 insertions, 9 deletions
diff --git a/src/sound.c b/src/sound.c
index 0fbeceb4b9e..2ceefd3bce3 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -73,6 +73,10 @@ Boston, MA 02110-1301, USA. */
73#ifdef HAVE_SOUNDCARD_H 73#ifdef HAVE_SOUNDCARD_H
74#include <soundcard.h> 74#include <soundcard.h>
75#endif 75#endif
76#ifdef HAVE_ALSA
77#include <asoundlib.h>
78#endif
79
76/* END: Non Windows Includes */ 80/* END: Non Windows Includes */
77 81
78#else /* WINDOWSNT */ 82#else /* WINDOWSNT */
@@ -121,6 +125,9 @@ static int parse_sound P_ ((Lisp_Object, Lisp_Object *));
121#ifndef DEFAULT_SOUND_DEVICE 125#ifndef DEFAULT_SOUND_DEVICE
122#define DEFAULT_SOUND_DEVICE "/dev/dsp" 126#define DEFAULT_SOUND_DEVICE "/dev/dsp"
123#endif 127#endif
128#ifndef DEFAULT_ALSA_SOUND_DEVICE
129#define DEFAULT_ALSA_SOUND_DEVICE "default"
130#endif
124 131
125 132
126/* Structure forward declarations. */ 133/* Structure forward declarations. */
@@ -227,6 +234,10 @@ struct sound_device
227 void (* choose_format) P_ ((struct sound_device *sd, 234 void (* choose_format) P_ ((struct sound_device *sd,
228 struct sound *s)); 235 struct sound *s));
229 236
237 /* Return a preferred data size in bytes to be sent to write (below)
238 each time. 2048 is used if this is NULL. */
239 int (* period_size) P_ ((struct sound_device *sd));
240
230 /* Write NYBTES bytes from BUFFER to device SD. */ 241 /* Write NYBTES bytes from BUFFER to device SD. */
231 void (* write) P_ ((struct sound_device *sd, const char *buffer, 242 void (* write) P_ ((struct sound_device *sd, const char *buffer,
232 int nbytes)); 243 int nbytes));
@@ -280,7 +291,7 @@ static void vox_open P_ ((struct sound_device *));
280static void vox_configure P_ ((struct sound_device *)); 291static void vox_configure P_ ((struct sound_device *));
281static void vox_close P_ ((struct sound_device *sd)); 292static void vox_close P_ ((struct sound_device *sd));
282static void vox_choose_format P_ ((struct sound_device *, struct sound *)); 293static void vox_choose_format P_ ((struct sound_device *, struct sound *));
283static void vox_init P_ ((struct sound_device *)); 294static int vox_init P_ ((struct sound_device *));
284static void vox_write P_ ((struct sound_device *, const char *, int)); 295static void vox_write P_ ((struct sound_device *, const char *, int));
285static void find_sound_type P_ ((struct sound *)); 296static void find_sound_type P_ ((struct sound *));
286static u_int32_t le2hl P_ ((u_int32_t)); 297static u_int32_t le2hl P_ ((u_int32_t));
@@ -604,7 +615,7 @@ wav_play (s, sd)
604 { 615 {
605 char *buffer; 616 char *buffer;
606 int nbytes; 617 int nbytes;
607 int blksize = 2048; 618 int blksize = sd->period_size ? sd->period_size (sd) : 2048;
608 619
609 buffer = (char *) alloca (blksize); 620 buffer = (char *) alloca (blksize);
610 lseek (s->fd, sizeof *header, SEEK_SET); 621 lseek (s->fd, sizeof *header, SEEK_SET);
@@ -633,7 +644,8 @@ enum au_encoding
633 AU_ENCODING_32, 644 AU_ENCODING_32,
634 AU_ENCODING_IEEE32, 645 AU_ENCODING_IEEE32,
635 AU_ENCODING_IEEE64, 646 AU_ENCODING_IEEE64,
636 AU_COMPRESSED = 23 647 AU_COMPRESSED = 23,
648 AU_ENCODING_ALAW_8 = 27
637}; 649};
638 650
639 651
@@ -689,7 +701,7 @@ au_play (s, sd)
689 SBYTES (s->data) - header->data_offset); 701 SBYTES (s->data) - header->data_offset);
690 else 702 else
691 { 703 {
692 int blksize = 2048; 704 int blksize = sd->period_size ? sd->period_size (sd) : 2048;
693 char *buffer; 705 char *buffer;
694 int nbytes; 706 int nbytes;
695 707
@@ -868,16 +880,33 @@ vox_choose_format (sd, s)
868/* Initialize device SD. Set up the interface functions in the device 880/* Initialize device SD. Set up the interface functions in the device
869 structure. */ 881 structure. */
870 882
871static void 883static int
872vox_init (sd) 884vox_init (sd)
873 struct sound_device *sd; 885 struct sound_device *sd;
874{ 886{
887 char *file;
888 int fd;
889
890 /* Open the sound device. Default is /dev/dsp. */
891 if (sd->file)
892 file = sd->file;
893 else
894 file = DEFAULT_SOUND_DEVICE;
895 fd = emacs_open (file, O_WRONLY, 0);
896 if (fd >= 0)
897 emacs_close (fd);
898 else
899 return 0;
900
875 sd->fd = -1; 901 sd->fd = -1;
876 sd->open = vox_open; 902 sd->open = vox_open;
877 sd->close = vox_close; 903 sd->close = vox_close;
878 sd->configure = vox_configure; 904 sd->configure = vox_configure;
879 sd->choose_format = vox_choose_format; 905 sd->choose_format = vox_choose_format;
880 sd->write = vox_write; 906 sd->write = vox_write;
907 sd->period_size = NULL;
908
909 return 1;
881} 910}
882 911
883/* Write NBYTES bytes from BUFFER to device SD. */ 912/* Write NBYTES bytes from BUFFER to device SD. */
@@ -893,6 +922,359 @@ vox_write (sd, buffer, nbytes)
893 sound_perror ("Error writing to sound device"); 922 sound_perror ("Error writing to sound device");
894} 923}
895 924
925#ifdef HAVE_ALSA
926/***********************************************************************
927 ALSA Driver Interface
928 ***********************************************************************/
929
930/* This driver is available on GNU/Linux. */
931
932static void
933alsa_sound_perror (msg, err)
934 char *msg;
935 int err;
936{
937 error ("%s: %s", msg, snd_strerror (err));
938}
939
940struct alsa_params
941{
942 snd_pcm_t *handle;
943 snd_pcm_hw_params_t *hwparams;
944 snd_pcm_sw_params_t *swparams;
945 snd_pcm_uframes_t period_size;
946};
947
948/* Open device SD. If SD->file is non-null, open that device,
949 otherwise use a default device name. */
950
951static void
952alsa_open (sd)
953 struct sound_device *sd;
954{
955 char *file;
956 struct alsa_params *p;
957 int err;
958
959 /* Open the sound device. Default is "default". */
960 if (sd->file)
961 file = sd->file;
962 else
963 file = DEFAULT_ALSA_SOUND_DEVICE;
964
965 p = xmalloc (sizeof (*p));
966 p->handle = NULL;
967 p->hwparams = NULL;
968 p->swparams = NULL;
969
970 sd->fd = -1;
971 sd->data = p;
972
973
974 if ((err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
975 alsa_sound_perror (file, err);
976}
977
978static int
979alsa_period_size (sd)
980 struct sound_device *sd;
981{
982 struct alsa_params *p = (struct alsa_params *) sd->data;
983 return p->period_size;
984}
985
986static void
987alsa_configure (sd)
988 struct sound_device *sd;
989{
990 int val, err, dir;
991 struct alsa_params *p = (struct alsa_params *) sd->data;
992 snd_pcm_uframes_t buffer_size;
993
994 xassert (p->handle != 0);
995
996 if ((err = snd_pcm_hw_params_malloc (&p->hwparams)) < 0)
997 alsa_sound_perror ("Could not allocate hardware parameter structure", err);
998
999 if ((err = snd_pcm_sw_params_malloc (&p->swparams)) < 0)
1000 alsa_sound_perror ("Could not allocate software parameter structure", err);
1001
1002 if ((err = snd_pcm_hw_params_any (p->handle, p->hwparams)) < 0)
1003 alsa_sound_perror ("Could not initialize hardware parameter structure", err);
1004
1005 if ((err = snd_pcm_hw_params_set_access (p->handle, p->hwparams,
1006 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
1007 alsa_sound_perror ("Could not set access type", err);
1008
1009 val = sd->format;
1010 if ((err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val)) < 0)
1011 alsa_sound_perror ("Could not set sound format", err);
1012
1013 val = sd->sample_rate;
1014 if ((err = snd_pcm_hw_params_set_rate_near (p->handle, p->hwparams, &val, 0))
1015 < 0)
1016 alsa_sound_perror ("Could not set sample rate", err);
1017
1018 val = sd->channels;
1019 if ((err = snd_pcm_hw_params_set_channels (p->handle, p->hwparams, val)) < 0)
1020 alsa_sound_perror ("Could not set channel count", err);
1021
1022
1023 err = snd_pcm_hw_params_get_period_size (p->hwparams, &p->period_size, &dir);
1024 if (err < 0)
1025 alsa_sound_perror ("Unable to get period size for playback", err);
1026
1027 err = snd_pcm_hw_params_get_buffer_size (p->hwparams, &buffer_size);
1028 if (err < 0)
1029 alsa_sound_perror("Unable to get buffer size for playback", err);
1030
1031 if ((err = snd_pcm_hw_params (p->handle, p->hwparams)) < 0)
1032 alsa_sound_perror ("Could not set parameters", err);
1033
1034 err = snd_pcm_sw_params_current (p->handle, p->swparams);
1035 if (err < 0)
1036 alsa_sound_perror ("Unable to determine current swparams for playback",
1037 err);
1038
1039 /* Start the transfer when the buffer is almost full */
1040 err = snd_pcm_sw_params_set_start_threshold (p->handle, p->swparams,
1041 (buffer_size / p->period_size)
1042 * p->period_size);
1043 if (err < 0)
1044 alsa_sound_perror ("Unable to set start threshold mode for playback", err);
1045
1046 /* Allow the transfer when at least period_size samples can be processed */
1047 err = snd_pcm_sw_params_set_avail_min (p->handle, p->swparams, p->period_size);
1048 if (err < 0)
1049 alsa_sound_perror ("Unable to set avail min for playback", err);
1050
1051 /* Align all transfers to 1 period */
1052 err = snd_pcm_sw_params_set_xfer_align (p->handle, p->swparams,
1053 p->period_size);
1054 if (err < 0)
1055 alsa_sound_perror ("Unable to set transfer align for playback", err);
1056
1057 err = snd_pcm_sw_params (p->handle, p->swparams);
1058 if (err < 0)
1059 alsa_sound_perror ("Unable to set sw params for playback\n", err);
1060
1061 snd_pcm_hw_params_free (p->hwparams);
1062 p->hwparams = NULL;
1063 snd_pcm_sw_params_free (p->swparams);
1064 p->swparams = NULL;
1065
1066 if ((err = snd_pcm_prepare (p->handle)) < 0)
1067 alsa_sound_perror ("Could not prepare audio interface for use", err);
1068
1069 if (sd->volume > 0)
1070 {
1071 int chn;
1072 snd_mixer_t *handle;
1073 snd_mixer_elem_t *e;
1074 char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
1075
1076 if (snd_mixer_open (&handle, 0) >= 0)
1077 {
1078 if (snd_mixer_attach (handle, file) >= 0
1079 && snd_mixer_load (handle) >= 0
1080 && snd_mixer_selem_register (handle, NULL, NULL) >= 0)
1081 for (e = snd_mixer_first_elem (handle);
1082 e;
1083 e = snd_mixer_elem_next (e))
1084 {
1085 if (snd_mixer_selem_has_playback_volume (e))
1086 {
1087 long pmin, pmax;
1088 snd_mixer_selem_get_playback_volume_range (e, &pmin, &pmax);
1089 long vol = pmin + (sd->volume * (pmax - pmin)) / 100;
1090
1091 for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++)
1092 snd_mixer_selem_set_playback_volume (e, chn, vol);
1093 }
1094 }
1095 snd_mixer_close(handle);
1096 }
1097 }
1098}
1099
1100
1101/* Close device SD if it is open. */
1102
1103static void
1104alsa_close (sd)
1105 struct sound_device *sd;
1106{
1107 struct alsa_params *p = (struct alsa_params *) sd->data;
1108 if (p)
1109 {
1110 if (p->hwparams)
1111 snd_pcm_hw_params_free (p->hwparams);
1112 if (p->swparams)
1113 snd_pcm_sw_params_free (p->swparams);
1114 if (p->handle)
1115 {
1116 snd_pcm_drain(p->handle);
1117 snd_pcm_close (p->handle);
1118 }
1119 free (p);
1120 }
1121}
1122
1123/* Choose device-dependent format for device SD from sound file S. */
1124
1125static void
1126alsa_choose_format (sd, s)
1127 struct sound_device *sd;
1128 struct sound *s;
1129{
1130 struct alsa_params *p = (struct alsa_params *) sd->data;
1131 if (s->type == RIFF)
1132 {
1133 struct wav_header *h = (struct wav_header *) s->header;
1134 if (h->precision == 8)
1135 sd->format = SND_PCM_FORMAT_U8;
1136 else if (h->precision == 16)
1137 sd->format = SND_PCM_FORMAT_S16_LE;
1138 else
1139 error ("Unsupported WAV file format");
1140 }
1141 else if (s->type == SUN_AUDIO)
1142 {
1143 struct au_header *header = (struct au_header *) s->header;
1144 switch (header->encoding)
1145 {
1146 case AU_ENCODING_ULAW_8:
1147 sd->format = SND_PCM_FORMAT_MU_LAW;
1148 break;
1149 case AU_ENCODING_ALAW_8:
1150 sd->format = SND_PCM_FORMAT_A_LAW;
1151 break;
1152 case AU_ENCODING_IEEE32:
1153 sd->format = SND_PCM_FORMAT_FLOAT_BE;
1154 break;
1155 case AU_ENCODING_IEEE64:
1156 sd->format = SND_PCM_FORMAT_FLOAT64_BE;
1157 break;
1158 case AU_ENCODING_8:
1159 sd->format = SND_PCM_FORMAT_S8;
1160 break;
1161 case AU_ENCODING_16:
1162 sd->format = SND_PCM_FORMAT_S16_BE;
1163 break;
1164 case AU_ENCODING_24:
1165 sd->format = SND_PCM_FORMAT_S24_BE;
1166 break;
1167 case AU_ENCODING_32:
1168 sd->format = SND_PCM_FORMAT_S32_BE;
1169 break;
1170
1171 default:
1172 error ("Unsupported AU file format");
1173 }
1174 }
1175 else
1176 abort ();
1177}
1178
1179
1180/* Write NBYTES bytes from BUFFER to device SD. */
1181
1182static void
1183alsa_write (sd, buffer, nbytes)
1184 struct sound_device *sd;
1185 const char *buffer;
1186 int nbytes;
1187{
1188 struct alsa_params *p = (struct alsa_params *) sd->data;
1189
1190 /* The the third parameter to snd_pcm_writei is frames, not bytes. */
1191 int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
1192 int nwritten = 0;
1193 int err;
1194
1195 while (nwritten < nbytes)
1196 {
1197 if ((err = snd_pcm_writei (p->handle,
1198 buffer + nwritten,
1199 (nbytes - nwritten)/fact)) < 0)
1200 {
1201 fprintf(stderr, "Err %d/%s\n", err, snd_strerror(err));
1202 if (err == -EPIPE)
1203 { /* under-run */
1204 err = snd_pcm_prepare (p->handle);
1205 if (err < 0)
1206 alsa_sound_perror ("Can't recover from underrun, prepare failed",
1207 err);
1208 }
1209 else if (err == -ESTRPIPE)
1210 {
1211 while ((err = snd_pcm_resume (p->handle)) == -EAGAIN)
1212 sleep(1); /* wait until the suspend flag is released */
1213 if (err < 0)
1214 {
1215 err = snd_pcm_prepare (p->handle);
1216 if (err < 0)
1217 alsa_sound_perror ("Can't recover from suspend, "
1218 "prepare failed",
1219 err);
1220 }
1221 }
1222 else
1223 alsa_sound_perror ("Error writing to sound device", err);
1224
1225 }
1226 else
1227 nwritten += err * fact;
1228 }
1229}
1230
1231static void
1232snd_error_quiet (file, line, function, err, fmt)
1233 const char *file;
1234 int line;
1235 const char *function;
1236 int err;
1237 const char *fmt;
1238{
1239}
1240
1241/* Initialize device SD. Set up the interface functions in the device
1242 structure. */
1243
1244static int
1245alsa_init (sd)
1246 struct sound_device *sd;
1247{
1248 char *file;
1249 snd_pcm_t *handle;
1250 int err;
1251
1252 /* Open the sound device. Default is "default". */
1253 if (sd->file)
1254 file = sd->file;
1255 else
1256 file = DEFAULT_ALSA_SOUND_DEVICE;
1257
1258 snd_lib_error_set_handler ((snd_lib_error_handler_t) snd_error_quiet);
1259 err = snd_pcm_open (&handle, file, SND_PCM_STREAM_PLAYBACK, 0);
1260 snd_lib_error_set_handler (NULL);
1261 if (err < 0)
1262 return 0;
1263
1264 sd->fd = -1;
1265 sd->open = alsa_open;
1266 sd->close = alsa_close;
1267 sd->configure = alsa_configure;
1268 sd->choose_format = alsa_choose_format;
1269 sd->write = alsa_write;
1270 sd->period_size = alsa_period_size;
1271
1272 return 1;
1273}
1274
1275#endif /* HAVE_ALSA */
1276
1277
896/* END: Non Windows functions */ 1278/* END: Non Windows functions */
897#else /* WINDOWSNT */ 1279#else /* WINDOWSNT */
898 1280
@@ -1056,10 +1438,11 @@ Internal use only, use `play-sound' instead.\n */)
1056 args[1] = sound; 1438 args[1] = sound;
1057 Frun_hook_with_args (2, args); 1439 Frun_hook_with_args (2, args);
1058 1440
1059 /* There is only one type of device we currently support, the VOX 1441#ifdef HAVE_ALSA
1060 sound driver. Set up the device interface functions for that 1442 if (!alsa_init (current_sound_device))
1061 device. */ 1443#endif
1062 vox_init (current_sound_device); 1444 if (!vox_init (current_sound_device))
1445 error ("No usable sound device driver found");
1063 1446
1064 /* Open the device. */ 1447 /* Open the device. */
1065 current_sound_device->open (current_sound_device); 1448 current_sound_device->open (current_sound_device);