diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
commit | 526b5580dabbfed7cfe5439dc3a90ec727f563c2 (patch) | |
tree | 22b1af92348785daad16714ee5e2b633017e0e48 /apps/plugins/pdbox/PDa/src/s_audio_alsa.c | |
parent | 4f2dfcc01b260d946044ef2b6af5fe36cb772c8d (diff) | |
download | rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.tar.gz rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.zip |
Cut the files in half and it might work better (note to self: check your tree is really clean before patching)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio_alsa.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_audio_alsa.c | 944 |
1 files changed, 0 insertions, 944 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_alsa.c b/apps/plugins/pdbox/PDa/src/s_audio_alsa.c index 87d7cb929b..b8e8535dc9 100644 --- a/apps/plugins/pdbox/PDa/src/s_audio_alsa.c +++ b/apps/plugins/pdbox/PDa/src/s_audio_alsa.c | |||
@@ -943,948 +943,4 @@ void alsa_getdevs(char *indevlist, int *nindevs, | |||
943 | } | 943 | } |
944 | *nindevs = *noutdevs = j; | 944 | *nindevs = *noutdevs = j; |
945 | } | 945 | } |
946 | /* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler, | ||
947 | * Winfried Ritsch, Karl MacMillan, and others. | ||
948 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
949 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
950 | |||
951 | /* this file inputs and outputs audio using the ALSA API available on linux. */ | ||
952 | |||
953 | #include <alsa/asoundlib.h> | ||
954 | |||
955 | #include "m_pd.h" | ||
956 | #include "s_stuff.h" | ||
957 | #include <errno.h> | ||
958 | #include <stdio.h> | ||
959 | #include <unistd.h> | ||
960 | #include <stdlib.h> | ||
961 | #include <string.h> | ||
962 | #include <sys/types.h> | ||
963 | #include <sys/time.h> | ||
964 | #include <sys/stat.h> | ||
965 | #include <sys/ioctl.h> | ||
966 | #include <fcntl.h> | ||
967 | #include <sched.h> | ||
968 | #include <sys/mman.h> | ||
969 | |||
970 | typedef int16_t t_alsa_sample16; | ||
971 | typedef int32_t t_alsa_sample32; | ||
972 | #define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16) | ||
973 | #define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32) | ||
974 | #define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE) | ||
975 | #define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE) | ||
976 | #define ALSA_MAXDEV 1 | ||
977 | #define ALSA_JITTER 1024 | ||
978 | #define ALSA_EXTRABUFFER 2048 | ||
979 | #define ALSA_DEFFRAGSIZE 64 | ||
980 | #define ALSA_DEFNFRAG 12 | ||
981 | |||
982 | #ifndef INT32_MAX | ||
983 | #define INT32_MAX 0x7fffffff | ||
984 | #endif | ||
985 | |||
986 | #if (SND_LIB_MAJOR < 1) | ||
987 | #define ALSAAPI9 | ||
988 | #endif | ||
989 | |||
990 | typedef struct _alsa_dev | ||
991 | { | ||
992 | snd_pcm_t *inhandle; | ||
993 | snd_pcm_t *outhandle; | ||
994 | int innoninterleave; /* true if we're set for noninterleaved read */ | ||
995 | int outnoninterleave; /* same for write */ | ||
996 | } t_alsa_dev; | ||
997 | |||
998 | t_alsa_dev alsa_device; | ||
999 | static void *alsa_snd_buf = 0; | ||
1000 | static void **alsa_buf_ptrs; | ||
1001 | static int alsa_samplewidth; | ||
1002 | static snd_pcm_status_t* in_status; | ||
1003 | static snd_pcm_status_t* out_status; | ||
1004 | |||
1005 | static int alsa_mode; | ||
1006 | static int alsa_buf_samps; /* believed actual ALSA bufsize in sample frames */ | ||
1007 | static int alsa_inchannels; | ||
1008 | static int alsa_outchannels; | ||
1009 | |||
1010 | /* Defines */ | ||
1011 | #define DEBUG(x) x | ||
1012 | #define DEBUG2(x) {x;} | ||
1013 | |||
1014 | static void alsa_checkiosync( void); | ||
1015 | static void alsa_numbertoname(int devno, char *devname, int nchar); | ||
1016 | |||
1017 | /* don't assume we can turn all 31 bits when doing float-to-fix; | ||
1018 | otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ | ||
1019 | #define FMAX 0x7ffff000 | ||
1020 | #define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) | ||
1021 | |||
1022 | /* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */ | ||
1023 | |||
1024 | static void check_error(int err, const char *why) | ||
1025 | { | ||
1026 | if (err < 0) | ||
1027 | fprintf(stderr, "%s: %s\n", why, snd_strerror(err)); | ||
1028 | } | ||
1029 | |||
1030 | /* was: alsa_open_audio(int wantinchans, int wantoutchans, int srate) */ | ||
1031 | |||
1032 | int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, | ||
1033 | int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, | ||
1034 | int *choutdev, int rate) | ||
1035 | { | ||
1036 | int err, inchans = 0, outchans = 0, subunitdir; | ||
1037 | char devname[512]; | ||
1038 | snd_pcm_hw_params_t* hw_params; | ||
1039 | snd_pcm_sw_params_t* sw_params; | ||
1040 | snd_output_t* out; | ||
1041 | int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE); | ||
1042 | int nfrags, i; | ||
1043 | short* tmp_buf; | ||
1044 | unsigned int tmp_uint; | ||
1045 | snd_pcm_uframes_t tmp_snd_pcm_uframes; | ||
1046 | int wantinchans, wantoutchans, devno; | ||
1047 | |||
1048 | if (naudioindev >= 2 || naudiooutdev >= 2) | ||
1049 | post("alsa: only one input and output device allowed (extras ignored"); | ||
1050 | if (naudioindev >= 1 && naudiooutdev >= 1 && | ||
1051 | audioindev[0] != audiooutdev[0]) | ||
1052 | post("alsa: changing output device to agree with input device"); | ||
1053 | if (nchindev) | ||
1054 | wantinchans = chindev[0]; | ||
1055 | else wantinchans = (naudioindev ? 2 : 0); | ||
1056 | if (nchoutdev) | ||
1057 | wantoutchans = choutdev[0]; | ||
1058 | else wantoutchans = (naudiooutdev ? 2 : 0); | ||
1059 | devno = (naudioindev > 0 ? audioindev[0] : | ||
1060 | (naudiooutdev > 0 ? audiooutdev[0] : 0)); | ||
1061 | |||
1062 | alsa_numbertoname(devno, devname, 512); | ||
1063 | |||
1064 | if (sys_verbose) | ||
1065 | post("device name %s; channels in %d, out %d", devname, wantinchans, | ||
1066 | wantoutchans); | ||
1067 | |||
1068 | nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size); | ||
1069 | /* save our belief as to ALSA's buffer size for later */ | ||
1070 | alsa_buf_samps = nfrags * frag_size; | ||
1071 | |||
1072 | if (sys_verbose) | ||
1073 | post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); | ||
1074 | |||
1075 | alsa_device.innoninterleave = alsa_device.outnoninterleave = 0; | ||
1076 | if (wantinchans) | ||
1077 | { | ||
1078 | err = snd_pcm_open(&alsa_device.inhandle, devname, | ||
1079 | SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); | ||
1080 | |||
1081 | check_error(err, "snd_pcm_open (input)"); | ||
1082 | if (err < 0) | ||
1083 | inchans = 0; | ||
1084 | else | ||
1085 | { | ||
1086 | inchans = wantinchans; | ||
1087 | snd_pcm_nonblock(alsa_device.inhandle, 1); | ||
1088 | } | ||
1089 | } | ||
1090 | if (wantoutchans) | ||
1091 | { | ||
1092 | err = snd_pcm_open(&alsa_device.outhandle, devname, | ||
1093 | SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | ||
1094 | |||
1095 | check_error(err, "snd_pcm_open (output)"); | ||
1096 | if (err < 0) | ||
1097 | outchans = 0; | ||
1098 | else | ||
1099 | { | ||
1100 | outchans = wantoutchans; | ||
1101 | snd_pcm_nonblock(alsa_device.outhandle, 1); | ||
1102 | } | ||
1103 | } | ||
1104 | if (inchans) | ||
1105 | { | ||
1106 | if (sys_verbose) | ||
1107 | post("opening sound input..."); | ||
1108 | err = snd_pcm_hw_params_malloc(&hw_params); | ||
1109 | check_error(err, "snd_pcm_hw_params_malloc (input)"); | ||
1110 | |||
1111 | // get the default params | ||
1112 | err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params); | ||
1113 | check_error(err, "snd_pcm_hw_params_any (input)"); | ||
1114 | |||
1115 | /* try to set interleaved access */ | ||
1116 | err = snd_pcm_hw_params_set_access(alsa_device.inhandle, | ||
1117 | hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); | ||
1118 | if (err < 0) | ||
1119 | { | ||
1120 | /* OK, so try non-interleaved */ | ||
1121 | err = snd_pcm_hw_params_set_access(alsa_device.inhandle, | ||
1122 | hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); | ||
1123 | if (err >= 0) | ||
1124 | { | ||
1125 | post("using non-interleaved audio input"); | ||
1126 | alsa_device.innoninterleave = 1; | ||
1127 | } | ||
1128 | } | ||
1129 | check_error(err, "snd_pcm_hw_params_set_access (input)"); | ||
1130 | // Try to set 32 bit format first | ||
1131 | err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, | ||
1132 | SND_PCM_FORMAT_S32); | ||
1133 | if (err < 0) | ||
1134 | { | ||
1135 | /* fprintf(stderr, | ||
1136 | "PD-ALSA: 32 bit format not available - using 16\n"); */ | ||
1137 | err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, | ||
1138 | SND_PCM_FORMAT_S16); | ||
1139 | check_error(err, "snd_pcm_hw_params_set_format (input)"); | ||
1140 | alsa_samplewidth = 2; | ||
1141 | } | ||
1142 | else | ||
1143 | { | ||
1144 | alsa_samplewidth = 4; | ||
1145 | } | ||
1146 | post("Sample width set to %d bytes", alsa_samplewidth); | ||
1147 | // set the subformat | ||
1148 | err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params, | ||
1149 | SND_PCM_SUBFORMAT_STD); | ||
1150 | check_error(err, "snd_pcm_hw_params_set_subformat (input)"); | ||
1151 | // set the number of channels | ||
1152 | tmp_uint = inchans; | ||
1153 | err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle, | ||
1154 | hw_params, &tmp_uint); | ||
1155 | check_error(err, "snd_pcm_hw_params_set_channels (input)"); | ||
1156 | if (tmp_uint != (unsigned)inchans) | ||
1157 | post("ALSA: set input channels to %d", tmp_uint); | ||
1158 | inchans = tmp_uint; | ||
1159 | // set the sampling rate | ||
1160 | err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params, | ||
1161 | &rate, 0); | ||
1162 | check_error(err, "snd_pcm_hw_params_set_rate_min (input)"); | ||
1163 | #if 0 | ||
1164 | err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); | ||
1165 | post("input sample rate %d", err); | ||
1166 | #endif | ||
1167 | // set the period - ie frag size | ||
1168 | // post("fragsize a %d", frag_size); | ||
1169 | |||
1170 | /* LATER try this to get a recommended period size... | ||
1171 | right now, it trips an assertion failure in ALSA lib */ | ||
1172 | #if 0 | ||
1173 | post("input period was %d, min %d, max %d\n", | ||
1174 | snd_pcm_hw_params_get_period_size(hw_params, 0), | ||
1175 | snd_pcm_hw_params_get_period_size_min(hw_params, 0), | ||
1176 | snd_pcm_hw_params_get_period_size_max(hw_params, 0)); | ||
1177 | #endif | ||
1178 | #ifdef ALSAAPI9 | ||
1179 | err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle, | ||
1180 | hw_params, | ||
1181 | (snd_pcm_uframes_t) | ||
1182 | frag_size, 0); | ||
1183 | #else | ||
1184 | tmp_snd_pcm_uframes = frag_size; | ||
1185 | err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle, | ||
1186 | hw_params, &tmp_snd_pcm_uframes, 0); | ||
1187 | #endif | ||
1188 | check_error(err, "snd_pcm_hw_params_set_period_size_near (input)"); | ||
1189 | // post("fragsize b %d", frag_size); | ||
1190 | // set the number of periods - ie numfrags | ||
1191 | // post("nfrags a %d", nfrags); | ||
1192 | #ifdef ALSAAPI9 | ||
1193 | err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle, | ||
1194 | hw_params, nfrags, 0); | ||
1195 | #else | ||
1196 | tmp_uint = nfrags; | ||
1197 | err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle, | ||
1198 | hw_params, &tmp_uint, 0); | ||
1199 | #endif | ||
1200 | check_error(err, "snd_pcm_hw_params_set_periods_near (input)"); | ||
1201 | // set the buffer size | ||
1202 | #ifdef ALSAAPI9 | ||
1203 | err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle, | ||
1204 | hw_params, nfrags * frag_size); | ||
1205 | #else | ||
1206 | tmp_snd_pcm_uframes = nfrags * frag_size; | ||
1207 | err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle, | ||
1208 | hw_params, &tmp_snd_pcm_uframes); | ||
1209 | #endif | ||
1210 | check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)"); | ||
1211 | |||
1212 | err = snd_pcm_hw_params(alsa_device.inhandle, hw_params); | ||
1213 | check_error(err, "snd_pcm_hw_params (input)"); | ||
1214 | |||
1215 | snd_pcm_hw_params_free(hw_params); | ||
1216 | |||
1217 | err = snd_pcm_sw_params_malloc(&sw_params); | ||
1218 | check_error(err, "snd_pcm_sw_params_malloc (input)"); | ||
1219 | err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params); | ||
1220 | check_error(err, "snd_pcm_sw_params_current (input)"); | ||
1221 | err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, | ||
1222 | sw_params, nfrags * frag_size); | ||
1223 | check_error(err, "snd_pcm_sw_params_set_start_threshold (input)"); | ||
1224 | err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, | ||
1225 | sw_params, 0x7fffffff); | ||
1226 | check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)"); | ||
1227 | err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params, | ||
1228 | frag_size); | ||
1229 | check_error(err, "snd_pcm_sw_params_set_avail_min (input)"); | ||
1230 | err = snd_pcm_sw_params(alsa_device.inhandle, sw_params); | ||
1231 | check_error(err, "snd_pcm_sw_params (input)"); | ||
1232 | |||
1233 | snd_pcm_sw_params_free(sw_params); | ||
1234 | |||
1235 | snd_output_stdio_attach(&out, stderr, 0); | ||
1236 | #if 0 | ||
1237 | if (sys_verbose) | ||
1238 | { | ||
1239 | snd_pcm_dump_hw_setup(alsa_device.inhandle, out); | ||
1240 | snd_pcm_dump_sw_setup(alsa_device.inhandle, out); | ||
1241 | } | ||
1242 | #endif | ||
1243 | } | ||
1244 | |||
1245 | if (outchans) | ||
1246 | { | ||
1247 | int foo; | ||
1248 | if (sys_verbose) | ||
1249 | post("opening sound output..."); | ||
1250 | err = snd_pcm_hw_params_malloc(&hw_params); | ||
1251 | check_error(err, "snd_pcm_sw_params (output)"); | ||
1252 | |||
1253 | // get the default params | ||
1254 | err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params); | ||
1255 | check_error(err, "snd_pcm_hw_params_any (output)"); | ||
1256 | // set interleaved access - FIXME deal with other access types | ||
1257 | err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params, | ||
1258 | SND_PCM_ACCESS_RW_INTERLEAVED); | ||
1259 | check_error(err, "snd_pcm_hw_params_set_access (output)"); | ||
1260 | |||
1261 | /* try to set interleaved access */ | ||
1262 | err = snd_pcm_hw_params_set_access(alsa_device.outhandle, | ||
1263 | hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); | ||
1264 | if (err < 0) | ||
1265 | { | ||
1266 | /* OK, so try non-interleaved */ | ||
1267 | err = snd_pcm_hw_params_set_access(alsa_device.outhandle, | ||
1268 | hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); | ||
1269 | if (err >= 0) | ||
1270 | { | ||
1271 | post("using non-interleaved audio"); | ||
1272 | alsa_device.outnoninterleave = 1; | ||
1273 | } | ||
1274 | } | ||
1275 | check_error(err, "snd_pcm_hw_params_set_access (output)"); | ||
1276 | |||
1277 | |||
1278 | // Try to set 32 bit format first | ||
1279 | err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params, | ||
1280 | SND_PCM_FORMAT_S32); | ||
1281 | if (err < 0) | ||
1282 | { | ||
1283 | err = snd_pcm_hw_params_set_format(alsa_device.outhandle, | ||
1284 | hw_params,SND_PCM_FORMAT_S16); | ||
1285 | check_error(err, "snd_pcm_hw_params_set_format (output)"); | ||
1286 | /* fprintf(stderr, | ||
1287 | "PD-ALSA: 32 bit format not available - using 16\n"); */ | ||
1288 | alsa_samplewidth = 2; | ||
1289 | } | ||
1290 | else | ||
1291 | { | ||
1292 | alsa_samplewidth = 4; | ||
1293 | } | ||
1294 | // set the subformat | ||
1295 | err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params, | ||
1296 | SND_PCM_SUBFORMAT_STD); | ||
1297 | check_error(err, "snd_pcm_hw_params_set_subformat (output)"); | ||
1298 | // set the number of channels | ||
1299 | tmp_uint = outchans; | ||
1300 | err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle, | ||
1301 | hw_params, &tmp_uint); | ||
1302 | check_error(err, "snd_pcm_hw_params_set_channels (output)"); | ||
1303 | if (tmp_uint != (unsigned)outchans) | ||
1304 | post("alsa: set output channels to %d", tmp_uint); | ||
1305 | outchans = tmp_uint; | ||
1306 | // set the sampling rate | ||
1307 | err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params, | ||
1308 | &rate, 0); | ||
1309 | check_error(err, "snd_pcm_hw_params_set_rate_min (output)"); | ||
1310 | #if 0 | ||
1311 | err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); | ||
1312 | post("output sample rate %d", err); | ||
1313 | #endif | ||
1314 | // set the period - ie frag size | ||
1315 | #if 0 | ||
1316 | post("output period was %d, min %d, max %d\n", | ||
1317 | snd_pcm_hw_params_get_period_size(hw_params, 0), | ||
1318 | snd_pcm_hw_params_get_period_size_min(hw_params, 0), | ||
1319 | snd_pcm_hw_params_get_period_size_max(hw_params, 0)); | ||
1320 | #endif | ||
1321 | // post("fragsize c %d", frag_size); | ||
1322 | #ifdef ALSAAPI9 | ||
1323 | err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle, | ||
1324 | hw_params, | ||
1325 | (snd_pcm_uframes_t) | ||
1326 | frag_size, 0); | ||
1327 | #else | ||
1328 | tmp_snd_pcm_uframes = frag_size; | ||
1329 | err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle, | ||
1330 | hw_params, &tmp_snd_pcm_uframes, 0); | ||
1331 | #endif | ||
1332 | // post("fragsize d %d", frag_size); | ||
1333 | check_error(err, "snd_pcm_hw_params_set_period_size_near (output)"); | ||
1334 | // set the number of periods - ie numfrags | ||
1335 | #ifdef ALSAAPI9 | ||
1336 | err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle, | ||
1337 | hw_params, nfrags, 0); | ||
1338 | #else | ||
1339 | tmp_uint = nfrags; | ||
1340 | err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle, | ||
1341 | hw_params, &tmp_uint, 0); | ||
1342 | #endif | ||
1343 | check_error(err, "snd_pcm_hw_params_set_periods_near (output)"); | ||
1344 | // set the buffer size | ||
1345 | #ifdef ALSAAPI9 | ||
1346 | err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle, | ||
1347 | hw_params, nfrags * frag_size); | ||
1348 | #else | ||
1349 | tmp_snd_pcm_uframes = nfrags * frag_size; | ||
1350 | err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle, | ||
1351 | hw_params, &tmp_snd_pcm_uframes); | ||
1352 | #endif | ||
1353 | check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)"); | ||
1354 | |||
1355 | err = snd_pcm_hw_params(alsa_device.outhandle, hw_params); | ||
1356 | check_error(err, "snd_pcm_hw_params (output)"); | ||
1357 | |||
1358 | snd_pcm_hw_params_free(hw_params); | ||
1359 | |||
1360 | err = snd_pcm_sw_params_malloc(&sw_params); | ||
1361 | check_error(err, "snd_pcm_sw_params_malloc (output)"); | ||
1362 | err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params); | ||
1363 | check_error(err, "snd_pcm_sw_params_current (output)"); | ||
1364 | err = snd_pcm_sw_params_set_start_threshold(alsa_device.outhandle, | ||
1365 | sw_params, nfrags * frag_size); | ||
1366 | check_error(err, "snd_pcm_sw_params_set_start_threshold (output)"); | ||
1367 | err = snd_pcm_sw_params_set_stop_threshold(alsa_device.outhandle, | ||
1368 | sw_params, 0x7fffffff); | ||
1369 | check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)"); | ||
1370 | err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params, | ||
1371 | frag_size); | ||
1372 | check_error(err, "snd_pcm_sw_params_set_avail_min (output)"); | ||
1373 | err = snd_pcm_sw_params(alsa_device.outhandle, sw_params); | ||
1374 | check_error(err, "snd_pcm_sw_params (output)"); | ||
1375 | snd_pcm_sw_params_free(sw_params); | ||
1376 | |||
1377 | snd_output_stdio_attach(&out, stderr, 0); | ||
1378 | #if 0 | ||
1379 | if (sys_verbose) | ||
1380 | { | ||
1381 | snd_pcm_dump_hw_setup(alsa_device.outhandle, out); | ||
1382 | snd_pcm_dump_sw_setup(alsa_device.outhandle, out); | ||
1383 | } | ||
1384 | #endif | ||
1385 | } | ||
1386 | |||
1387 | if (inchans) | ||
1388 | snd_pcm_prepare(alsa_device.inhandle); | ||
1389 | if (outchans) | ||
1390 | snd_pcm_prepare(alsa_device.outhandle); | ||
1391 | |||
1392 | // if duplex we can link the channels so they start together | ||
1393 | if (inchans && outchans) | ||
1394 | snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle); | ||
1395 | |||
1396 | // set up the status variables | ||
1397 | err = snd_pcm_status_malloc(&in_status); | ||
1398 | check_error(err, "snd_pcm_status_malloc"); | ||
1399 | err = snd_pcm_status_malloc(&out_status); | ||
1400 | check_error(err, "snd_pcm_status_malloc"); | ||
1401 | |||
1402 | // set up the buffer | ||
1403 | if (alsa_snd_buf) | ||
1404 | free(alsa_snd_buf); | ||
1405 | alsa_snd_buf = (void *)malloc( | ||
1406 | sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * | ||
1407 | (outchans > inchans ? outchans : inchans)); | ||
1408 | memset(alsa_snd_buf, 0, sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * | ||
1409 | (outchans > inchans ? outchans : inchans)); | ||
1410 | /* make an array of pointers too in case we need them */ | ||
1411 | if (alsa_buf_ptrs) | ||
1412 | free(alsa_buf_ptrs); | ||
1413 | alsa_buf_ptrs = (void **)malloc( | ||
1414 | sizeof(void *) * (outchans > inchans ? outchans : inchans)); | ||
1415 | for (i = 0; i < (outchans > inchans ? outchans : inchans); i++) | ||
1416 | alsa_buf_ptrs[i] = (t_alsa_sample32 *)alsa_snd_buf + i * DEFDACBLKSIZE; | ||
1417 | |||
1418 | // fill the buffer with silence | ||
1419 | if (outchans) | ||
1420 | { | ||
1421 | i = (frag_size * nfrags)/DEFDACBLKSIZE + 1; | ||
1422 | while (i--) | ||
1423 | { | ||
1424 | if (alsa_device.outnoninterleave) | ||
1425 | snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs, | ||
1426 | DEFDACBLKSIZE); | ||
1427 | else snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf, | ||
1428 | DEFDACBLKSIZE); | ||
1429 | } | ||
1430 | /* confused about this: */ | ||
1431 | /* if ((err = snd_pcm_start(alsa_device.outhandle) < 0)) | ||
1432 | check_error(err, "output start failed\n"); */ | ||
1433 | } | ||
1434 | else if (inchans) | ||
1435 | { | ||
1436 | if (snd_pcm_start(alsa_device.inhandle) < 0) | ||
1437 | check_error(err, "input start failed\n"); | ||
1438 | } | ||
1439 | alsa_outchannels = outchans; | ||
1440 | alsa_inchannels = inchans; | ||
1441 | |||
1442 | return (!(inchans || outchans)); | ||
1443 | } | ||
1444 | |||
1445 | void alsa_close_audio(void) | ||
1446 | { | ||
1447 | int err; | ||
1448 | if (alsa_inchannels) | ||
1449 | { | ||
1450 | err = snd_pcm_close(alsa_device.inhandle); | ||
1451 | check_error(err, "snd_pcm_close (input)"); | ||
1452 | } | ||
1453 | if (alsa_outchannels) | ||
1454 | { | ||
1455 | err = snd_pcm_close(alsa_device.outhandle); | ||
1456 | check_error(err, "snd_pcm_close (output)"); | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1460 | // #define DEBUG_ALSA_XFER | ||
1461 | |||
1462 | int alsa_send_dacs(void) | ||
1463 | { | ||
1464 | static int16_t *sp; | ||
1465 | static int xferno = 0; | ||
1466 | static int callno = 0; | ||
1467 | static double timenow; | ||
1468 | double timelast; | ||
1469 | t_sample *fp, *fp1, *fp2; | ||
1470 | int i, j, k, err, devno = 0; | ||
1471 | int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; | ||
1472 | int result; | ||
1473 | int inchannels = (sys_inchannels > alsa_inchannels ? | ||
1474 | alsa_inchannels : sys_inchannels); | ||
1475 | int outchannels = (sys_outchannels > alsa_outchannels ? | ||
1476 | alsa_outchannels : sys_outchannels); | ||
1477 | unsigned int intransfersize = DEFDACBLKSIZE; | ||
1478 | unsigned int outtransfersize = DEFDACBLKSIZE; | ||
1479 | |||
1480 | // get the status | ||
1481 | if (!inchannels && !outchannels) | ||
1482 | { | ||
1483 | return SENDDACS_NO; | ||
1484 | } | ||
1485 | |||
1486 | timelast = timenow; | ||
1487 | timenow = sys_getrealtime(); | ||
1488 | |||
1489 | #ifdef DEBUG_ALSA_XFER | ||
1490 | if (timenow - timelast > 0.050) | ||
1491 | fprintf(stderr, "(%d)", | ||
1492 | (int)(1000 * (timenow - timelast))), fflush(stderr); | ||
1493 | #endif | ||
1494 | |||
1495 | callno++; | ||
1496 | |||
1497 | alsa_checkiosync(); /* check I/O are in sync and data not late */ | ||
1498 | |||
1499 | if (alsa_inchannels) | ||
1500 | { | ||
1501 | snd_pcm_status(alsa_device.inhandle, in_status); | ||
1502 | if (snd_pcm_status_get_avail(in_status) < intransfersize) | ||
1503 | return SENDDACS_NO; | ||
1504 | } | ||
1505 | if (alsa_outchannels) | ||
1506 | { | ||
1507 | snd_pcm_status(alsa_device.outhandle, out_status); | ||
1508 | if (snd_pcm_status_get_avail(out_status) < outtransfersize) | ||
1509 | return SENDDACS_NO; | ||
1510 | } | ||
1511 | |||
1512 | /* do output */ | ||
1513 | if (alsa_outchannels) | ||
1514 | { | ||
1515 | fp = sys_soundout; | ||
1516 | if (alsa_samplewidth == 4) | ||
1517 | { | ||
1518 | if (alsa_device.outnoninterleave) | ||
1519 | { | ||
1520 | int n = outchannels * DEFDACBLKSIZE; | ||
1521 | for (i = 0, fp1 = fp; i < n; i++) | ||
1522 | { | ||
1523 | float s1 = *fp1 * INT32_MAX; | ||
1524 | ((t_alsa_sample32 *)alsa_snd_buf)[i] = CLIP32(s1); | ||
1525 | } | ||
1526 | n = alsa_outchannels * DEFDACBLKSIZE; | ||
1527 | for (; i < n; i++) | ||
1528 | ((t_alsa_sample32 *)alsa_snd_buf)[i] = 0; | ||
1529 | } | ||
1530 | else | ||
1531 | { | ||
1532 | for (i = 0, fp1 = fp; i < outchannels; i++, | ||
1533 | fp1 += DEFDACBLKSIZE) | ||
1534 | { | ||
1535 | for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | ||
1536 | j += alsa_outchannels, fp2++) | ||
1537 | { | ||
1538 | float s1 = *fp2 * INT32_MAX; | ||
1539 | ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1); | ||
1540 | } | ||
1541 | } | ||
1542 | } | ||
1543 | } | ||
1544 | else | ||
1545 | { | ||
1546 | for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE) | ||
1547 | { | ||
1548 | for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | ||
1549 | j += alsa_outchannels, fp2++) | ||
1550 | { | ||
1551 | int s = *fp2 * 32767.; | ||
1552 | if (s > 32767) | ||
1553 | s = 32767; | ||
1554 | else if (s < -32767) | ||
1555 | s = -32767; | ||
1556 | ((t_alsa_sample16 *)alsa_snd_buf)[j] = s; | ||
1557 | } | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | if (alsa_device.outnoninterleave) | ||
1562 | result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs, | ||
1563 | outtransfersize); | ||
1564 | else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf, | ||
1565 | outtransfersize); | ||
1566 | |||
1567 | if (result != (int)outtransfersize) | ||
1568 | { | ||
1569 | #ifdef DEBUG_ALSA_XFER | ||
1570 | if (result >= 0 || errno == EAGAIN) | ||
1571 | fprintf(stderr, "ALSA: write returned %d of %d\n", | ||
1572 | result, outtransfersize); | ||
1573 | else fprintf(stderr, "ALSA: write: %s\n", | ||
1574 | snd_strerror(errno)); | ||
1575 | fprintf(stderr, | ||
1576 | "inputcount %d, outputcount %d, outbufsize %d\n", | ||
1577 | inputcount, outputcount, | ||
1578 | (ALSA_EXTRABUFFER + sys_advance_samples) | ||
1579 | * alsa_samplewidth * outchannels); | ||
1580 | #endif | ||
1581 | sys_log_error(ERR_DACSLEPT); | ||
1582 | return (SENDDACS_NO); | ||
1583 | } | ||
1584 | |||
1585 | /* zero out the output buffer */ | ||
1586 | memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) * | ||
1587 | sys_outchannels); | ||
1588 | if (sys_getrealtime() - timenow > 0.002) | ||
1589 | { | ||
1590 | #ifdef DEBUG_ALSA_XFER | ||
1591 | fprintf(stderr, "output %d took %d msec\n", | ||
1592 | callno, (int)(1000 * (timenow - timelast))), fflush(stderr); | ||
1593 | #endif | ||
1594 | timenow = sys_getrealtime(); | ||
1595 | sys_log_error(ERR_DACSLEPT); | ||
1596 | } | ||
1597 | } | ||
1598 | /* do input */ | ||
1599 | if (alsa_inchannels) | ||
1600 | { | ||
1601 | if (alsa_device.innoninterleave) | ||
1602 | result = snd_pcm_readn(alsa_device.inhandle, alsa_buf_ptrs, | ||
1603 | intransfersize); | ||
1604 | else result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf, | ||
1605 | intransfersize); | ||
1606 | if (result < (int)intransfersize) | ||
1607 | { | ||
1608 | #ifdef DEBUG_ALSA_XFER | ||
1609 | if (result < 0) | ||
1610 | fprintf(stderr, | ||
1611 | "snd_pcm_read %d %d: %s\n", | ||
1612 | callno, xferno, snd_strerror(errno)); | ||
1613 | else fprintf(stderr, | ||
1614 | "snd_pcm_read %d %d returned only %d\n", | ||
1615 | callno, xferno, result); | ||
1616 | fprintf(stderr, | ||
1617 | "inputcount %d, outputcount %d, inbufsize %d\n", | ||
1618 | inputcount, outputcount, | ||
1619 | (ALSA_EXTRABUFFER + sys_advance_samples) | ||
1620 | * alsa_samplewidth * inchannels); | ||
1621 | #endif | ||
1622 | sys_log_error(ERR_ADCSLEPT); | ||
1623 | return (SENDDACS_NO); | ||
1624 | } | ||
1625 | fp = sys_soundin; | ||
1626 | if (alsa_samplewidth == 4) | ||
1627 | { | ||
1628 | if (alsa_device.innoninterleave) | ||
1629 | { | ||
1630 | int n = inchannels * DEFDACBLKSIZE; | ||
1631 | for (i = 0, fp1 = fp; i < n; i++) | ||
1632 | *fp1 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[i] | ||
1633 | * (1./ INT32_MAX); | ||
1634 | } | ||
1635 | else | ||
1636 | { | ||
1637 | for (i = 0, fp1 = fp; i < inchannels; | ||
1638 | i++, fp1 += DEFDACBLKSIZE) | ||
1639 | { | ||
1640 | for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | ||
1641 | j += alsa_inchannels, fp2++) | ||
1642 | *fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j] | ||
1643 | * (1./ INT32_MAX); | ||
1644 | } | ||
1645 | } | ||
1646 | } | ||
1647 | else | ||
1648 | { | ||
1649 | for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE) | ||
1650 | { | ||
1651 | for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | ||
1652 | j += alsa_inchannels, fp2++) | ||
1653 | *fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j] | ||
1654 | * 3.051850e-05; | ||
1655 | } | ||
1656 | } | ||
1657 | } | ||
1658 | xferno++; | ||
1659 | if (sys_getrealtime() - timenow > 0.002) | ||
1660 | { | ||
1661 | #ifdef DEBUG_ALSA_XFER | ||
1662 | fprintf(stderr, "routine took %d msec\n", | ||
1663 | (int)(1000 * (sys_getrealtime() - timenow))); | ||
1664 | #endif | ||
1665 | sys_log_error(ERR_ADCSLEPT); | ||
1666 | } | ||
1667 | return SENDDACS_YES; | ||
1668 | } | ||
1669 | |||
1670 | void alsa_printstate( void) | ||
1671 | { | ||
1672 | int i, result; | ||
1673 | snd_pcm_sframes_t indelay, outdelay; | ||
1674 | if (sys_audioapi != API_ALSA) | ||
1675 | { | ||
1676 | error("restart-audio: implemented for ALSA only."); | ||
1677 | return; | ||
1678 | } | ||
1679 | if (sys_inchannels) | ||
1680 | { | ||
1681 | result = snd_pcm_delay(alsa_device.inhandle, &indelay); | ||
1682 | if (result < 0) | ||
1683 | post("snd_pcm_delay 1 failed"); | ||
1684 | else post("in delay %d", indelay); | ||
1685 | } | ||
1686 | if (sys_outchannels) | ||
1687 | { | ||
1688 | result = snd_pcm_delay(alsa_device.outhandle, &outdelay); | ||
1689 | if (result < 0) | ||
1690 | post("snd_pcm_delay 2 failed"); | ||
1691 | else post("out delay %d", outdelay); | ||
1692 | } | ||
1693 | post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64); | ||
1694 | |||
1695 | post("buf samples %d", alsa_buf_samps); | ||
1696 | } | ||
1697 | |||
1698 | |||
1699 | void alsa_resync( void) | ||
1700 | { | ||
1701 | int i, result; | ||
1702 | if (sys_audioapi != API_ALSA) | ||
1703 | { | ||
1704 | error("restart-audio: implemented for ALSA only."); | ||
1705 | return; | ||
1706 | } | ||
1707 | memset(alsa_snd_buf, 0, | ||
1708 | sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * sys_outchannels); | ||
1709 | for (i = 0; i < 1000000; i++) | ||
1710 | { | ||
1711 | if (alsa_device.outnoninterleave) | ||
1712 | result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs, | ||
1713 | DEFDACBLKSIZE); | ||
1714 | else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf, | ||
1715 | DEFDACBLKSIZE); | ||
1716 | if (result != (int)DEFDACBLKSIZE) | ||
1717 | break; | ||
1718 | } | ||
1719 | post("%d written", i); | ||
1720 | } | ||
1721 | |||
1722 | void alsa_putzeros(int n) | ||
1723 | { | ||
1724 | int i, result; | ||
1725 | memset(alsa_snd_buf, 0, | ||
1726 | sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * alsa_outchannels); | ||
1727 | for (i = 0; i < n; i++) | ||
1728 | { | ||
1729 | if (alsa_device.outnoninterleave) | ||
1730 | result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs, | ||
1731 | DEFDACBLKSIZE); | ||
1732 | else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf, | ||
1733 | DEFDACBLKSIZE); | ||
1734 | #if 0 | ||
1735 | if (result != DEFDACBLKSIZE) | ||
1736 | post("result %d", result); | ||
1737 | #endif | ||
1738 | } | ||
1739 | /* post ("putzeros %d", n); */ | ||
1740 | } | ||
1741 | |||
1742 | void alsa_getzeros(int n) | ||
1743 | { | ||
1744 | int i, result; | ||
1745 | for (i = 0; i < n; i++) | ||
1746 | { | ||
1747 | result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf, | ||
1748 | DEFDACBLKSIZE); | ||
1749 | #if 0 | ||
1750 | if (result != DEFDACBLKSIZE) | ||
1751 | post("result %d", result); | ||
1752 | #endif | ||
1753 | } | ||
1754 | /* post ("getzeros %d", n); */ | ||
1755 | } | ||
1756 | |||
1757 | /* call this only if both input and output are open */ | ||
1758 | static void alsa_checkiosync( void) | ||
1759 | { | ||
1760 | int i, result, checkit = 1, giveup = 1000, alreadylogged = 0; | ||
1761 | snd_pcm_sframes_t indelay, outdelay, defect; | ||
1762 | |||
1763 | if (!(alsa_outchannels && alsa_inchannels)) | ||
1764 | return; | ||
1765 | while (checkit) | ||
1766 | { | ||
1767 | checkit = 0; | ||
1768 | if (giveup-- <= 0) | ||
1769 | return; | ||
1770 | result = snd_pcm_delay(alsa_device.outhandle, &outdelay); | ||
1771 | if (result < 0) | ||
1772 | { | ||
1773 | post("output snd_pcm_delay failed: %s", snd_strerror(result)); | ||
1774 | if (snd_pcm_status(alsa_device.outhandle, out_status) < 0) | ||
1775 | post("output snd_pcm_status failed"); | ||
1776 | else post("astate %d", | ||
1777 | snd_pcm_status_get_state(out_status)); | ||
1778 | return; | ||
1779 | } | ||
1780 | if (outdelay < 0) | ||
1781 | sys_log_error(ERR_DATALATE), alreadylogged = 1; | ||
1782 | |||
1783 | if (sys_inchannels) | ||
1784 | { | ||
1785 | result = snd_pcm_delay(alsa_device.inhandle, &indelay); | ||
1786 | if (result < 0) | ||
1787 | { | ||
1788 | post("input snd_pcm_delay failed"); | ||
1789 | return; | ||
1790 | } | ||
1791 | defect = indelay + outdelay - alsa_buf_samps; | ||
1792 | if (defect < -(3 * DEFDACBLKSIZE / 2) ) | ||
1793 | { | ||
1794 | checkit = 1; | ||
1795 | alsa_putzeros(1); | ||
1796 | if (!alreadylogged) | ||
1797 | sys_log_error(ERR_RESYNC), alreadylogged = 1; | ||
1798 | } | ||
1799 | else if (defect > 0) | ||
1800 | { | ||
1801 | checkit = 1; | ||
1802 | alsa_getzeros(1); | ||
1803 | if (!alreadylogged) | ||
1804 | sys_log_error(ERR_RESYNC), alreadylogged = 1; | ||
1805 | } | ||
1806 | /* if (alreadylogged) | ||
1807 | post("in %d out %d defect %d", indelay, outdelay, defect); */ | ||
1808 | } | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1812 | static int alsa_nnames = 0; | ||
1813 | static char **alsa_names = 0; | ||
1814 | |||
1815 | void alsa_adddev(char *name) | ||
1816 | { | ||
1817 | if (alsa_nnames) | ||
1818 | alsa_names = (char **)t_resizebytes(alsa_names, | ||
1819 | alsa_nnames * sizeof(char *), | ||
1820 | (alsa_nnames+1) * sizeof(char *)); | ||
1821 | else alsa_names = (char **)t_getbytes(sizeof(char *)); | ||
1822 | alsa_names[alsa_nnames] = gensym(name)->s_name; | ||
1823 | alsa_nnames++; | ||
1824 | } | ||
1825 | |||
1826 | static void alsa_numbertoname(int devno, char *devname, int nchar) | ||
1827 | { | ||
1828 | int ndev = 0, cardno = -1; | ||
1829 | while (!snd_card_next(&cardno) && cardno >= 0) | ||
1830 | ndev++; | ||
1831 | if (devno < 2*ndev) | ||
1832 | { | ||
1833 | if (devno & 1) | ||
1834 | snprintf(devname, nchar, "plughw:%d", devno/2); | ||
1835 | else snprintf(devname, nchar, "hw:%d", devno/2); | ||
1836 | } | ||
1837 | else if (devno <2*ndev + alsa_nnames) | ||
1838 | snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]); | ||
1839 | else snprintf(devname, nchar, "???"); | ||
1840 | } | ||
1841 | 946 | ||
1842 | /* For each hardware card found, we list two devices, the "hard" and | ||
1843 | "plug" one. The card scan is derived from portaudio code. */ | ||
1844 | void alsa_getdevs(char *indevlist, int *nindevs, | ||
1845 | char *outdevlist, int *noutdevs, int *canmulti, | ||
1846 | int maxndev, int devdescsize) | ||
1847 | { | ||
1848 | int ndev = 0, cardno = -1, i, j; | ||
1849 | *canmulti = 0; /* only one device; must be the same for input&output */ | ||
1850 | while (!snd_card_next(&cardno) && cardno >= 0) | ||
1851 | { | ||
1852 | snd_ctl_t *ctl; | ||
1853 | snd_ctl_card_info_t *info; | ||
1854 | char devname[80]; | ||
1855 | const char *desc; | ||
1856 | if (2 * ndev + 2 > maxndev) | ||
1857 | break; | ||
1858 | /* apparently, "cardno" is just a counter; but check that here */ | ||
1859 | if (ndev != cardno) | ||
1860 | fprintf(stderr, "oops: ALSA cards not reported in order?\n"); | ||
1861 | sprintf(devname, "hw:%d", cardno ); | ||
1862 | /* fprintf(stderr, "\ntry %s...\n", devname); */ | ||
1863 | if (snd_ctl_open(&ctl, devname, 0) >= 0) | ||
1864 | { | ||
1865 | snd_ctl_card_info_malloc(&info); | ||
1866 | snd_ctl_card_info(ctl, info); | ||
1867 | desc = snd_ctl_card_info_get_name(info); | ||
1868 | snd_ctl_card_info_free(info); | ||
1869 | } | ||
1870 | else | ||
1871 | { | ||
1872 | fprintf(stderr, "ALSA card scan error\n"); | ||
1873 | desc = "???"; | ||
1874 | } | ||
1875 | /* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */ | ||
1876 | sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc); | ||
1877 | sprintf(indevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc); | ||
1878 | sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc); | ||
1879 | sprintf(outdevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc); | ||
1880 | ndev++; | ||
1881 | } | ||
1882 | for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++) | ||
1883 | { | ||
1884 | if (j >= maxndev) | ||
1885 | break; | ||
1886 | snprintf(indevlist + j * devdescsize, devdescsize, "%s", | ||
1887 | alsa_names[i]); | ||
1888 | } | ||
1889 | *nindevs = *noutdevs = j; | ||
1890 | } | ||