N-sim
Emulation and simulation of
Wireless Sensor Networks



   Home


   Project Page


   Download


   CVS



   Installation


   Configuration


   Plug-ins




 Hosted by
SourceForge.net Logo

/home/brennan/n-sim/Vaike/linux/system-addons/drivers/raw_audio.c

Go to the documentation of this file.
00001 
00014 /*
00015  * Copyright 2007. Los Alamos National Security, LLC. This material
00016  * was produced under U.S. Government contract DE-AC52-06NA25396 for
00017  * Los Alamos National Laboratory (LANL), which is operated by Los
00018  * Alamos National Security, LLC, for the Department of Energy. The
00019  * U.S. Government has rights to use, reproduce, and distribute this
00020  * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY,
00021  * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
00022  * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to
00023  * produce derivative works, such modified software should be clearly
00024  * marked, so as not to confuse it with the version available from LANL.
00025  *
00026  * Additionally, this program is free software; you can redistribute
00027  * it and/or modify it under the terms of the GNU General Public
00028  * License as published by the Free Software Foundation; version 2 of
00029  * the License. Accordingly, this program is distributed in the hope
00030  * it will be useful, but WITHOUT ANY WARRANTY; without even the
00031  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00032  * PURPOSE. See the GNU General Public License for more details.
00033  */
00034 
00035 #define _GNU_SOURCE
00036 #include <stdio.h>
00037 #include <malloc.h>
00038 #include <unistd.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <getopt.h>
00042 #include <fcntl.h>
00043 #include <ctype.h>
00044 #include <errno.h>
00045 #include <limits.h>
00046 #include <locale.h>
00047 #include <alsa/asoundlib.h>
00048 #include <assert.h>
00049 #include <sys/types.h>
00050 #include <sys/poll.h>
00051 #include <sys/uio.h>
00052 #include <sys/time.h>
00053 #include <sys/signal.h>
00054 #include <sys/socket.h>
00055 #include <netinet/in.h>
00056 #include <arpa/inet.h>
00057 #include <asm/byteorder.h>
00058 
00059 #if 0
00060 #include "aconfig.h"
00061 #include "gettext.h"
00062 #include "formats.h"
00063 #include "version.h"
00064 #endif
00065 
00066 // FIXME: convert to miniSoap
00067 
00068 #ifndef LLONG_MAX
00069 #define LLONG_MAX    9223372036854775807LL
00070 #endif
00071 
00072 #define DEFAULT_FORMAT          SND_PCM_FORMAT_U8
00073 #define DEFAULT_SPEED           4000
00074 
00075 #define FORMAT_DEFAULT          -1
00076 #define FORMAT_RAW              0
00077 #define FORMAT_VOC              1
00078 #define FORMAT_WAVE             2
00079 #define FORMAT_AU               3
00080 
00081 
00082 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
00083 #define error(...) do {\
00084         fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
00085         fprintf(stderr, __VA_ARGS__); \
00086         putc('\n', stderr); \
00087 } while (0)
00088 #else
00089 #define error(args...) do {\
00090         fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
00091         fprintf(stderr, ##args); \
00092         putc('\n', stderr); \
00093 } while (0)
00094 #endif
00095 
00096 
00097 
00098 static snd_pcm_sframes_t (*readi_func)(snd_pcm_t *handle, void *buffer, snd_pcm_uframes_t size);
00099 
00100 static char *command;
00101 static snd_pcm_t *handle;
00102 static struct {
00103         snd_pcm_format_t format;
00104         unsigned int channels;
00105         unsigned int rate;
00106 } hwparams, rhwparams;
00107 static int timelimit = 10;  // 0 continues forever, but eventually fails
00108 static int quiet_mode = 0;
00109 static int file_type = FORMAT_RAW;
00110 static unsigned int sleep_min = 0;
00111 static int open_mode = 0;
00112 static snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
00113 static int mmap_flag = 0;
00114 static int interleaved = 1;
00115 static int nonblock = 0;
00116 static snd_pcm_uframes_t chunk_size = 0;
00117 static unsigned period_time = 0;
00118 static unsigned buffer_time = 0;
00119 static snd_pcm_uframes_t period_frames = 0;
00120 static snd_pcm_uframes_t buffer_frames = 0;
00121 static int avail_min = -1;
00122 static int start_delay = 0;
00123 static int stop_delay = 0;
00124 static int verbose = 0;
00125 static size_t bits_per_sample, bits_per_frame;
00126 static size_t chunk_bytes;
00127 static snd_output_t *log;
00128 struct timeval ttime;
00129 snd_pcm_info_t *info;
00130 static off64_t pbrec_count = LLONG_MAX;
00131 char *pcm_name = "default";
00132 
00133 
00134 
00135 static size_t set_params(void)
00136 {
00137         snd_pcm_hw_params_t *params;
00138         snd_pcm_sw_params_t *swparams;
00139         snd_pcm_uframes_t buffer_size;
00140         int err;
00141         size_t n;
00142         snd_pcm_uframes_t xfer_align;
00143         unsigned int rate;
00144         snd_pcm_uframes_t start_threshold, stop_threshold;
00145         snd_pcm_hw_params_alloca(&params);
00146         snd_pcm_sw_params_alloca(&swparams);
00147         err = snd_pcm_hw_params_any(handle, params);
00148         if (err < 0) {
00149                 error("Broken configuration for this PCM: no configurations available");
00150                 exit(EXIT_FAILURE);
00151         }
00152         if (mmap_flag) {
00153                 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
00154                 snd_pcm_access_mask_none(mask);
00155                 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
00156                 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
00157                 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
00158                 err = snd_pcm_hw_params_set_access_mask(handle, params, mask);
00159         } else if (interleaved)
00160                 err = snd_pcm_hw_params_set_access(handle, params,
00161                                                    SND_PCM_ACCESS_RW_INTERLEAVED);
00162         else
00163                 err = snd_pcm_hw_params_set_access(handle, params,
00164                                                    SND_PCM_ACCESS_RW_NONINTERLEAVED);
00165         if (err < 0) {
00166                 error("Access type not available");
00167                 exit(EXIT_FAILURE);
00168         }
00169         err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
00170         if (err < 0) {
00171                 error("Sample format non available");
00172                 exit(EXIT_FAILURE);
00173         }
00174         err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
00175         if (err < 0) {
00176                 error("Channels count non available");
00177                 exit(EXIT_FAILURE);
00178         }
00179 
00180 #if 0
00181         err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
00182         assert(err >= 0);
00183 #endif
00184         rate = hwparams.rate;
00185         err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
00186         assert(err >= 0);
00187         if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
00188                 if (!quiet_mode) {
00189                         char plugex[64];
00190                         const char *pcmname = snd_pcm_name(handle);
00191                         fprintf(stderr, "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n", rate, hwparams.rate);
00192                         if (! pcmname || strchr(snd_pcm_name(handle), ':'))
00193                                 *plugex = 0;
00194                         else
00195                                 snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
00196                                          snd_pcm_name(handle));
00197                         fprintf(stderr, "         please, try the plug plugin %s\n",
00198                                 plugex);
00199                 }
00200         }
00201         rate = hwparams.rate;
00202         if (buffer_time == 0 && buffer_frames == 0) {
00203                 err = snd_pcm_hw_params_get_buffer_time_max(params,
00204                                                             &buffer_time, 0);
00205                 assert(err >= 0);
00206                 if (buffer_time > 500000)
00207                         buffer_time = 500000;
00208         }
00209         if (period_time == 0 && period_frames == 0) {
00210                 if (buffer_time > 0)
00211                   period_time = buffer_time / 4;
00212                 
00213                 else
00214                   period_frames = buffer_frames / 4;
00215                 //period_frames = buffer_frames / 2;
00216         }
00217         if (period_time > 0)
00218                 err = snd_pcm_hw_params_set_period_time_near(handle, params,
00219                                                              &period_time, 0);
00220         else
00221                 err = snd_pcm_hw_params_set_period_size_near(handle, params,
00222                                                              &period_frames, 0);
00223         assert(err >= 0);
00224         if (buffer_time > 0) {
00225                 err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
00226                                                              &buffer_time, 0);
00227         } else {
00228                 err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
00229                                                              &buffer_frames);
00230         }
00231         assert(err >= 0);
00232         err = snd_pcm_hw_params(handle, params);
00233         if (err < 0) {
00234                 error("Unable to install hw params:");
00235                 snd_pcm_hw_params_dump(params, log);
00236                 exit(EXIT_FAILURE);
00237         }
00238         snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
00239         snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
00240         if (chunk_size == buffer_size) {
00241                 error("Can't use period equal to buffer size (%lu == %lu)",
00242                       chunk_size, buffer_size);
00243                 exit(EXIT_FAILURE);
00244         }
00245         snd_pcm_sw_params_current(handle, swparams);
00246         err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
00247         if (err < 0) {
00248                 error("Unable to obtain xfer align\n");
00249                 exit(EXIT_FAILURE);
00250         }
00251         if (sleep_min)
00252                 xfer_align = 1;
00253         err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
00254                                               sleep_min);
00255         assert(err >= 0);
00256         if (avail_min < 0)
00257                 n = chunk_size;
00258         else
00259                 n = (double) rate * avail_min / 1000000;
00260         err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
00261 
00262         /* round up to closest transfer boundary */
00263         n = (buffer_size / xfer_align) * xfer_align;
00264         if (start_delay <= 0) {
00265                 start_threshold = n + (double) rate * start_delay / 1000000;
00266         } else
00267                 start_threshold = (double) rate * start_delay / 1000000;
00268         if (start_threshold < 1)
00269                 start_threshold = 1;
00270         if (start_threshold > n)
00271                 start_threshold = n;
00272         err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00273         assert(err >= 0);
00274         if (stop_delay <= 0) 
00275                 stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
00276         else
00277                 stop_threshold = (double) rate * stop_delay / 1000000;
00278         err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00279         assert(err >= 0);
00280 
00281         err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
00282         assert(err >= 0);
00283 
00284         if (snd_pcm_sw_params(handle, swparams) < 0) {
00285                 error("unable to install sw params:");
00286                 snd_pcm_sw_params_dump(swparams, log);
00287                 exit(EXIT_FAILURE);
00288         }
00289 
00290         if (verbose)
00291                 snd_pcm_dump(handle, log);
00292 
00293         bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
00294         bits_per_frame = bits_per_sample * hwparams.channels;
00295         chunk_bytes = chunk_size * bits_per_frame / 8;
00296         return chunk_bytes;
00297 }
00298 
00299 
00300 int audio_open(void)
00301 {
00302         int error;
00303 
00304         snd_pcm_info_alloca(&info);
00305 
00306         error = snd_output_stdio_attach(&log, stderr, 0);
00307         assert(error >= 0);
00308 
00309         file_type = FORMAT_RAW;
00310         start_delay=1;
00311 
00312         chunk_size = -1;
00313         rhwparams.format = SND_PCM_FORMAT_U16_LE;
00314         rhwparams.rate = DEFAULT_SPEED;
00315         rhwparams.channels = 1;
00316 
00317         if ((error = snd_pcm_open(&handle, pcm_name, stream, open_mode)) < 0)
00318                 error("audio open error: %s", snd_strerror(error));
00319 
00320         if ((error = snd_pcm_info(handle, info)) < 0)
00321                 error("info error: %s", snd_strerror(error));
00322 
00323         if (nonblock) {
00324                 if ((error = snd_pcm_nonblock(handle, 1)) < 0)
00325                         error("nonblock setting error: %s",
00326                               snd_strerror(error));
00327         }
00328 
00329         chunk_size = 1024;
00330         hwparams = rhwparams;
00331 
00332         if (mmap_flag) {
00333                 readi_func = snd_pcm_mmap_readi;
00334         } else {
00335                 readi_func = snd_pcm_readi;
00336         }
00337 
00338         return set_params();
00339 }
00340 
00341 
00342 void audio_close(void)
00343 {
00344         snd_pcm_close(handle);
00345         snd_output_close(log);
00346         snd_config_update_free_global();
00347 }
00348 
00349 
00350 
00351 /**************************************************/
00352 /*
00353  * Safe read (for pipes)
00354  */
00355 #if 0 
00356 ssize_t safe_read(int fd, void *buf, size_t count)
00357 {
00358         ssize_t result = 0, res;
00359 
00360         while (count > 0) {
00361                 if ((res = read(fd, buf, count)) == 0)
00362                         break;
00363                 if (res < 0)
00364                         return result > 0 ? result : res;
00365                 count -= res;
00366                 result += res;
00367                 buf = (char *)buf + res;
00368         }
00369         return result;
00370 }
00371 #endif
00372 
00373 
00374 #ifndef timersub
00375 #define timersub(a, b, result) \
00376 do { \
00377         (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00378         (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00379         if ((result)->tv_usec < 0) { \
00380                 --(result)->tv_sec; \
00381                 (result)->tv_usec += 1000000; \
00382         } \
00383 } while (0)
00384 #endif
00385 
00386 
00387 /* I/O error handler */
00388 static void xrun(void)
00389 {
00390         snd_pcm_status_t *status;
00391         int res;
00392         
00393         snd_pcm_status_alloca(&status);
00394         if ((res = snd_pcm_status(handle, status))<0) {
00395                 error("status error: %s", snd_strerror(res));
00396                 exit(EXIT_FAILURE);
00397         }
00398         if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
00399                 struct timeval now, diff, tstamp;
00400                 gettimeofday(&now, 0);
00401                 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
00402                 timersub(&now, &tstamp, &diff);
00403                 fprintf(stderr, "%s!!! (at least %.3f ms long)\n",
00404                         stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun",
00405                         diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
00406                 if (verbose) {
00407                         fprintf(stderr, "Status:\n");
00408                         snd_pcm_status_dump(status, log);
00409                 }
00410                 if ((res = snd_pcm_prepare(handle))<0) {
00411                         error("xrun: prepare error: %s", snd_strerror(res));
00412                         exit(EXIT_FAILURE);
00413                 }
00414                 return;         /* ok, data should be accepted again */
00415         } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) {
00416                 if (verbose) {
00417                         fprintf(stderr, "Status(DRAINING):\n");
00418                         snd_pcm_status_dump(status, log);
00419                 }
00420                 if (stream == SND_PCM_STREAM_CAPTURE) {
00421                         fprintf(stderr, "capture stream format change? attempting recover...\n");
00422                         if ((res = snd_pcm_prepare(handle))<0) {
00423                                 error("xrun(DRAINING): prepare error: %s", snd_strerror(res));
00424                                 exit(EXIT_FAILURE);
00425                         }
00426                         return;
00427                 }
00428         }
00429         if (verbose) {
00430                 fprintf(stderr, "Status(R/W):\n");
00431                 snd_pcm_status_dump(status, log);
00432         }
00433         error("read/write error, state = %s", snd_pcm_state_name(snd_pcm_status_get_state(status)));
00434         exit(EXIT_FAILURE);
00435 }
00436 
00437 /* I/O suspend handler */
00438 static void suspend(void)
00439 {
00440         int res;
00441 
00442         if (!quiet_mode)
00443                 fprintf(stderr, "Suspended. Trying resume. "); fflush(stderr);
00444         while ((res = snd_pcm_resume(handle)) == -EAGAIN)
00445                 sleep(1);       /* wait until suspend flag is released */
00446         if (res < 0) {
00447                 if (!quiet_mode)
00448                         fprintf(stderr, "Failed. Restarting stream. "); fflush(stderr);
00449                 if ((res = snd_pcm_prepare(handle)) < 0) {
00450                         error("suspend: prepare error: %s", snd_strerror(res));
00451                         exit(EXIT_FAILURE);
00452                 }
00453         }
00454         if (!quiet_mode)
00455                 fprintf(stderr, "Done.\n");
00456 }
00457 
00458 
00459 /**************************************************/
00460 /**************************************************/
00461 
00462 /* peak handler */
00463 static void compute_max_peak(u_char *data, size_t count)
00464 {
00465         signed int val, max, max_peak = 0, perc;
00466         static  int     run = 0;
00467         int format_little_endian = snd_pcm_format_little_endian(hwparams.format);       
00468 
00469         switch (bits_per_sample) {
00470         case 8: {
00471                 signed char *valp = (signed char *)data;
00472                 signed char mask = snd_pcm_format_silence(hwparams.format);
00473                 while (count-- > 0) {
00474                         val = *valp++ ^ mask;
00475                         val = abs(val);
00476                         if (max_peak < val)
00477                                 max_peak = val;
00478                 }
00479                 break;
00480         }
00481         case 16: {
00482                 signed short *valp = (signed short *)data;
00483                 signed short mask = snd_pcm_format_silence_16(hwparams.format);
00484                 signed short sval;
00485 
00486                 count /= 2;
00487                 while (count-- > 0) {
00488                         if (format_little_endian)
00489                                 sval = __le16_to_cpu(*valp);
00490                         else    sval = __be16_to_cpu(*valp);
00491                         sval = abs(sval) ^ mask;
00492                         if (max_peak < sval)
00493                                 max_peak = sval;
00494                         valp++;
00495                 }
00496                 break;
00497         }
00498         case 24: {
00499                 unsigned char *valp = data;
00500                 signed int mask = snd_pcm_format_silence_32(hwparams.format);
00501 
00502                 count /= 3;
00503                 while (count-- > 0) {
00504                         if (format_little_endian) {
00505                                 val = valp[0] | (valp[1]<<8) | (valp[2]<<16);
00506                         } else {
00507                                 val = (valp[0]<<16) | (valp[1]<<8) | valp[2];
00508                         }
00509                         /* Correct signed bit in 32-bit value */
00510                         if (val & (1<<(bits_per_sample-1))) {
00511                                 val |= 0xff<<24;        /* Negate upper bits too */
00512                         }
00513                         val = abs(val) ^ mask;
00514                         if (max_peak < val)
00515                                 max_peak = val;
00516                         valp += 3;
00517                 }
00518                 break;
00519         }
00520         case 32: {
00521                 signed int *valp = (signed int *)data;
00522                 signed int mask = snd_pcm_format_silence_32(hwparams.format);
00523                 count /= 4;
00524                 while (count-- > 0) {
00525                         if (format_little_endian)
00526                                 val = __le32_to_cpu(*valp);
00527                         else    val = __be32_to_cpu(*valp);
00528                         val = abs(val) ^ mask;
00529                         if (max_peak < val)
00530                                 max_peak = val;
00531                         valp++;
00532                 }
00533                 break;
00534         }
00535         default:
00536                 if (run == 0) {
00537                         run = 1;
00538                 }
00539                 return;
00540         }
00541         max = 1 << (bits_per_sample-1);
00542         if (max <= 0)
00543                 max = 0x7fffffff;
00544 
00545         if (bits_per_sample > 16)
00546                 perc = max_peak / (max / 100);
00547         else
00548                 perc = max_peak * 100 / max;
00549 
00550 }
00551 
00552 
00553 int consume_audio(u_char *data, size_t rcount)
00554 {
00555         ssize_t r;
00556         size_t result = 0;
00557         size_t count = rcount;
00558 
00559         if (sleep_min == 0 &&
00560             count != chunk_size) {
00561                 count = chunk_size;
00562         }
00563 
00564         while (count > 0) {
00565                 r = readi_func(handle, data, count);
00566                 if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
00567                         snd_pcm_wait(handle, 1000);
00568                 } else if (r == -EPIPE) {
00569                         xrun();
00570                 } else if (r == -ESTRPIPE) {
00571                         suspend();
00572                 } else if (r < 0) {
00573                         error("read error: %s", snd_strerror(r));
00574                         exit(EXIT_FAILURE);
00575                 }
00576                 if (r > 0) {
00577                         if (verbose > 1)
00578                                 compute_max_peak(data, r * hwparams.channels);
00579                         result += r;
00580                         count -= r;
00581                         data += r * bits_per_frame / 8;
00582                 }
00583         }
00584         return rcount;
00585 }
00586 
00587 
00588 /* calculate the data count to read from/to dsp */
00589 static off64_t calc_count(void)
00590 {
00591         off64_t count;
00592 
00593         if (timelimit == 0) {
00594                 count = pbrec_count;
00595         } else {
00596                 count = snd_pcm_format_size(hwparams.format, hwparams.rate * hwparams.channels);
00597                 count *= (off64_t)timelimit;
00598         }
00599         return count < pbrec_count ? count : pbrec_count;
00600 }
00601 
00602 


© 2007, Los Alamos National Security, LLC.