1b815c7f3Sopenharmony_ci/* 2b815c7f3Sopenharmony_ci** Copyright (C) 1999-2018 Erik de Castro Lopo <erikd@mega-nerd.com> 3b815c7f3Sopenharmony_ci** 4b815c7f3Sopenharmony_ci** All rights reserved. 5b815c7f3Sopenharmony_ci** 6b815c7f3Sopenharmony_ci** Redistribution and use in source and binary forms, with or without 7b815c7f3Sopenharmony_ci** modification, are permitted provided that the following conditions are 8b815c7f3Sopenharmony_ci** met: 9b815c7f3Sopenharmony_ci** 10b815c7f3Sopenharmony_ci** * Redistributions of source code must retain the above copyright 11b815c7f3Sopenharmony_ci** notice, this list of conditions and the following disclaimer. 12b815c7f3Sopenharmony_ci** * Redistributions in binary form must reproduce the above copyright 13b815c7f3Sopenharmony_ci** notice, this list of conditions and the following disclaimer in 14b815c7f3Sopenharmony_ci** the documentation and/or other materials provided with the 15b815c7f3Sopenharmony_ci** distribution. 16b815c7f3Sopenharmony_ci** * Neither the author nor the names of any contributors may be used 17b815c7f3Sopenharmony_ci** to endorse or promote products derived from this software without 18b815c7f3Sopenharmony_ci** specific prior written permission. 19b815c7f3Sopenharmony_ci** 20b815c7f3Sopenharmony_ci** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21b815c7f3Sopenharmony_ci** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22b815c7f3Sopenharmony_ci** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23b815c7f3Sopenharmony_ci** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24b815c7f3Sopenharmony_ci** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25b815c7f3Sopenharmony_ci** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26b815c7f3Sopenharmony_ci** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27b815c7f3Sopenharmony_ci** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28b815c7f3Sopenharmony_ci** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29b815c7f3Sopenharmony_ci** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30b815c7f3Sopenharmony_ci** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31b815c7f3Sopenharmony_ci*/ 32b815c7f3Sopenharmony_ci 33b815c7f3Sopenharmony_ci#include "sfconfig.h" 34b815c7f3Sopenharmony_ci 35b815c7f3Sopenharmony_ci#include <stdio.h> 36b815c7f3Sopenharmony_ci#include <stdlib.h> 37b815c7f3Sopenharmony_ci#include <string.h> 38b815c7f3Sopenharmony_ci#include <errno.h> 39b815c7f3Sopenharmony_ci 40b815c7f3Sopenharmony_ci#if HAVE_UNISTD_H 41b815c7f3Sopenharmony_ci#include <unistd.h> 42b815c7f3Sopenharmony_ci#else 43b815c7f3Sopenharmony_ci#include "sf_unistd.h" 44b815c7f3Sopenharmony_ci#endif 45b815c7f3Sopenharmony_ci 46b815c7f3Sopenharmony_ci#include <sndfile.h> 47b815c7f3Sopenharmony_ci 48b815c7f3Sopenharmony_ci#include "common.h" 49b815c7f3Sopenharmony_ci 50b815c7f3Sopenharmony_ci#if HAVE_ALSA_ASOUNDLIB_H 51b815c7f3Sopenharmony_ci #define ALSA_PCM_NEW_HW_PARAMS_API 52b815c7f3Sopenharmony_ci #define ALSA_PCM_NEW_SW_PARAMS_API 53b815c7f3Sopenharmony_ci #include <alsa/asoundlib.h> 54b815c7f3Sopenharmony_ci #include <sys/time.h> 55b815c7f3Sopenharmony_ci#endif 56b815c7f3Sopenharmony_ci 57b815c7f3Sopenharmony_ci#if defined (__ANDROID__) 58b815c7f3Sopenharmony_ci 59b815c7f3Sopenharmony_ci#elif defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__) 60b815c7f3Sopenharmony_ci #include <fcntl.h> 61b815c7f3Sopenharmony_ci #include <sys/ioctl.h> 62b815c7f3Sopenharmony_ci #include <sys/soundcard.h> 63b815c7f3Sopenharmony_ci 64b815c7f3Sopenharmony_ci#elif HAVE_SNDIO_H 65b815c7f3Sopenharmony_ci #include <sndio.h> 66b815c7f3Sopenharmony_ci 67b815c7f3Sopenharmony_ci#elif (defined (sun) && defined (unix)) || defined(__NetBSD__) 68b815c7f3Sopenharmony_ci #include <fcntl.h> 69b815c7f3Sopenharmony_ci #include <sys/ioctl.h> 70b815c7f3Sopenharmony_ci #include <sys/audioio.h> 71b815c7f3Sopenharmony_ci 72b815c7f3Sopenharmony_ci#elif (OS_IS_WIN32 == 1) 73b815c7f3Sopenharmony_ci #include <windows.h> 74b815c7f3Sopenharmony_ci #include <mmsystem.h> 75b815c7f3Sopenharmony_ci 76b815c7f3Sopenharmony_ci#endif 77b815c7f3Sopenharmony_ci 78b815c7f3Sopenharmony_ci#define SIGNED_SIZEOF(x) ((int) sizeof (x)) 79b815c7f3Sopenharmony_ci#define BUFFER_LEN (2048) 80b815c7f3Sopenharmony_ci 81b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 82b815c7f3Sopenharmony_ci** Linux/OSS functions for playing a sound. 83b815c7f3Sopenharmony_ci*/ 84b815c7f3Sopenharmony_ci 85b815c7f3Sopenharmony_ci#if HAVE_ALSA_ASOUNDLIB_H 86b815c7f3Sopenharmony_ci 87b815c7f3Sopenharmony_cistatic snd_pcm_t * alsa_open (int channels, unsigned srate, int realtime) ; 88b815c7f3Sopenharmony_cistatic int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ; 89b815c7f3Sopenharmony_ci 90b815c7f3Sopenharmony_cistatic void 91b815c7f3Sopenharmony_cialsa_play (int argc, char *argv []) 92b815c7f3Sopenharmony_ci{ static float buffer [BUFFER_LEN] ; 93b815c7f3Sopenharmony_ci SNDFILE *sndfile ; 94b815c7f3Sopenharmony_ci SF_INFO sfinfo ; 95b815c7f3Sopenharmony_ci snd_pcm_t * alsa_dev ; 96b815c7f3Sopenharmony_ci int k, readcount, subformat ; 97b815c7f3Sopenharmony_ci 98b815c7f3Sopenharmony_ci for (k = 1 ; k < argc ; k++) 99b815c7f3Sopenharmony_ci { memset (&sfinfo, 0, sizeof (sfinfo)) ; 100b815c7f3Sopenharmony_ci 101b815c7f3Sopenharmony_ci printf ("Playing %s\n", argv [k]) ; 102b815c7f3Sopenharmony_ci if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) 103b815c7f3Sopenharmony_ci { puts (sf_strerror (NULL)) ; 104b815c7f3Sopenharmony_ci continue ; 105b815c7f3Sopenharmony_ci } ; 106b815c7f3Sopenharmony_ci 107b815c7f3Sopenharmony_ci if (sfinfo.channels < 1 || sfinfo.channels > 2) 108b815c7f3Sopenharmony_ci { printf ("Error : channels = %d.\n", sfinfo.channels) ; 109b815c7f3Sopenharmony_ci continue ; 110b815c7f3Sopenharmony_ci } ; 111b815c7f3Sopenharmony_ci 112b815c7f3Sopenharmony_ci if ((alsa_dev = alsa_open (sfinfo.channels, (unsigned) sfinfo.samplerate, SF_FALSE)) == NULL) 113b815c7f3Sopenharmony_ci continue ; 114b815c7f3Sopenharmony_ci 115b815c7f3Sopenharmony_ci subformat = sfinfo.format & SF_FORMAT_SUBMASK ; 116b815c7f3Sopenharmony_ci 117b815c7f3Sopenharmony_ci if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) 118b815c7f3Sopenharmony_ci { double scale ; 119b815c7f3Sopenharmony_ci int m ; 120b815c7f3Sopenharmony_ci 121b815c7f3Sopenharmony_ci sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; 122b815c7f3Sopenharmony_ci if (scale > 1.0) 123b815c7f3Sopenharmony_ci scale = 1.0 / scale ; 124b815c7f3Sopenharmony_ci else 125b815c7f3Sopenharmony_ci scale = 1.0 ; 126b815c7f3Sopenharmony_ci 127b815c7f3Sopenharmony_ci while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN))) 128b815c7f3Sopenharmony_ci { for (m = 0 ; m < readcount ; m++) 129b815c7f3Sopenharmony_ci buffer [m] *= scale ; 130b815c7f3Sopenharmony_ci alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ; 131b815c7f3Sopenharmony_ci } ; 132b815c7f3Sopenharmony_ci } 133b815c7f3Sopenharmony_ci else 134b815c7f3Sopenharmony_ci { while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN))) 135b815c7f3Sopenharmony_ci alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ; 136b815c7f3Sopenharmony_ci } ; 137b815c7f3Sopenharmony_ci 138b815c7f3Sopenharmony_ci snd_pcm_drain (alsa_dev) ; 139b815c7f3Sopenharmony_ci snd_pcm_close (alsa_dev) ; 140b815c7f3Sopenharmony_ci 141b815c7f3Sopenharmony_ci sf_close (sndfile) ; 142b815c7f3Sopenharmony_ci } ; 143b815c7f3Sopenharmony_ci 144b815c7f3Sopenharmony_ci return ; 145b815c7f3Sopenharmony_ci} /* alsa_play */ 146b815c7f3Sopenharmony_ci 147b815c7f3Sopenharmony_cistatic snd_pcm_t * 148b815c7f3Sopenharmony_cialsa_open (int channels, unsigned samplerate, int realtime) 149b815c7f3Sopenharmony_ci{ const char * device = "default" ; 150b815c7f3Sopenharmony_ci snd_pcm_t *alsa_dev = NULL ; 151b815c7f3Sopenharmony_ci snd_pcm_hw_params_t *hw_params ; 152b815c7f3Sopenharmony_ci snd_pcm_uframes_t buffer_size ; 153b815c7f3Sopenharmony_ci snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ; 154b815c7f3Sopenharmony_ci snd_pcm_sw_params_t *sw_params ; 155b815c7f3Sopenharmony_ci 156b815c7f3Sopenharmony_ci int err ; 157b815c7f3Sopenharmony_ci 158b815c7f3Sopenharmony_ci if (realtime) 159b815c7f3Sopenharmony_ci { alsa_period_size = 256 ; 160b815c7f3Sopenharmony_ci alsa_buffer_frames = 3 * alsa_period_size ; 161b815c7f3Sopenharmony_ci } 162b815c7f3Sopenharmony_ci else 163b815c7f3Sopenharmony_ci { alsa_period_size = 1024 ; 164b815c7f3Sopenharmony_ci alsa_buffer_frames = 4 * alsa_period_size ; 165b815c7f3Sopenharmony_ci } ; 166b815c7f3Sopenharmony_ci 167b815c7f3Sopenharmony_ci if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) 168b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ; 169b815c7f3Sopenharmony_ci goto catch_error ; 170b815c7f3Sopenharmony_ci } ; 171b815c7f3Sopenharmony_ci 172b815c7f3Sopenharmony_ci snd_pcm_nonblock (alsa_dev, 0) ; 173b815c7f3Sopenharmony_ci 174b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) 175b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ; 176b815c7f3Sopenharmony_ci goto catch_error ; 177b815c7f3Sopenharmony_ci } ; 178b815c7f3Sopenharmony_ci 179b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0) 180b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ; 181b815c7f3Sopenharmony_ci goto catch_error ; 182b815c7f3Sopenharmony_ci } ; 183b815c7f3Sopenharmony_ci 184b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 185b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ; 186b815c7f3Sopenharmony_ci goto catch_error ; 187b815c7f3Sopenharmony_ci } ; 188b815c7f3Sopenharmony_ci 189b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0) 190b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ; 191b815c7f3Sopenharmony_ci goto catch_error ; 192b815c7f3Sopenharmony_ci } ; 193b815c7f3Sopenharmony_ci 194b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0) 195b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ; 196b815c7f3Sopenharmony_ci goto catch_error ; 197b815c7f3Sopenharmony_ci } ; 198b815c7f3Sopenharmony_ci 199b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0) 200b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ; 201b815c7f3Sopenharmony_ci goto catch_error ; 202b815c7f3Sopenharmony_ci } ; 203b815c7f3Sopenharmony_ci 204b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0) 205b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ; 206b815c7f3Sopenharmony_ci goto catch_error ; 207b815c7f3Sopenharmony_ci } ; 208b815c7f3Sopenharmony_ci 209b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0) 210b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ; 211b815c7f3Sopenharmony_ci goto catch_error ; 212b815c7f3Sopenharmony_ci } ; 213b815c7f3Sopenharmony_ci 214b815c7f3Sopenharmony_ci if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0) 215b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ; 216b815c7f3Sopenharmony_ci goto catch_error ; 217b815c7f3Sopenharmony_ci } ; 218b815c7f3Sopenharmony_ci 219b815c7f3Sopenharmony_ci /* extra check: if we have only one period, this code won't work */ 220b815c7f3Sopenharmony_ci snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ; 221b815c7f3Sopenharmony_ci snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ; 222b815c7f3Sopenharmony_ci if (alsa_period_size == buffer_size) 223b815c7f3Sopenharmony_ci { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ; 224b815c7f3Sopenharmony_ci goto catch_error ; 225b815c7f3Sopenharmony_ci } ; 226b815c7f3Sopenharmony_ci 227b815c7f3Sopenharmony_ci snd_pcm_hw_params_free (hw_params) ; 228b815c7f3Sopenharmony_ci 229b815c7f3Sopenharmony_ci if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0) 230b815c7f3Sopenharmony_ci { fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ; 231b815c7f3Sopenharmony_ci goto catch_error ; 232b815c7f3Sopenharmony_ci } ; 233b815c7f3Sopenharmony_ci 234b815c7f3Sopenharmony_ci if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0) 235b815c7f3Sopenharmony_ci { fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ; 236b815c7f3Sopenharmony_ci goto catch_error ; 237b815c7f3Sopenharmony_ci } ; 238b815c7f3Sopenharmony_ci 239b815c7f3Sopenharmony_ci /* note: set start threshold to delay start until the ring buffer is full */ 240b815c7f3Sopenharmony_ci snd_pcm_sw_params_current (alsa_dev, sw_params) ; 241b815c7f3Sopenharmony_ci 242b815c7f3Sopenharmony_ci if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0) 243b815c7f3Sopenharmony_ci { fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ; 244b815c7f3Sopenharmony_ci goto catch_error ; 245b815c7f3Sopenharmony_ci } ; 246b815c7f3Sopenharmony_ci 247b815c7f3Sopenharmony_ci if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0) 248b815c7f3Sopenharmony_ci { fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ; 249b815c7f3Sopenharmony_ci goto catch_error ; 250b815c7f3Sopenharmony_ci } ; 251b815c7f3Sopenharmony_ci 252b815c7f3Sopenharmony_ci snd_pcm_sw_params_free (sw_params) ; 253b815c7f3Sopenharmony_ci 254b815c7f3Sopenharmony_ci snd_pcm_reset (alsa_dev) ; 255b815c7f3Sopenharmony_ci 256b815c7f3Sopenharmony_cicatch_error : 257b815c7f3Sopenharmony_ci 258b815c7f3Sopenharmony_ci if (err < 0 && alsa_dev != NULL) 259b815c7f3Sopenharmony_ci { snd_pcm_close (alsa_dev) ; 260b815c7f3Sopenharmony_ci return NULL ; 261b815c7f3Sopenharmony_ci } ; 262b815c7f3Sopenharmony_ci 263b815c7f3Sopenharmony_ci return alsa_dev ; 264b815c7f3Sopenharmony_ci} /* alsa_open */ 265b815c7f3Sopenharmony_ci 266b815c7f3Sopenharmony_cistatic int 267b815c7f3Sopenharmony_cialsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) 268b815c7f3Sopenharmony_ci{ static int epipe_count = 0 ; 269b815c7f3Sopenharmony_ci 270b815c7f3Sopenharmony_ci int total = 0 ; 271b815c7f3Sopenharmony_ci int retval ; 272b815c7f3Sopenharmony_ci 273b815c7f3Sopenharmony_ci if (epipe_count > 0) 274b815c7f3Sopenharmony_ci epipe_count -- ; 275b815c7f3Sopenharmony_ci 276b815c7f3Sopenharmony_ci while (total < frames) 277b815c7f3Sopenharmony_ci { retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ; 278b815c7f3Sopenharmony_ci 279b815c7f3Sopenharmony_ci if (retval >= 0) 280b815c7f3Sopenharmony_ci { total += retval ; 281b815c7f3Sopenharmony_ci if (total == frames) 282b815c7f3Sopenharmony_ci return total ; 283b815c7f3Sopenharmony_ci 284b815c7f3Sopenharmony_ci continue ; 285b815c7f3Sopenharmony_ci } ; 286b815c7f3Sopenharmony_ci 287b815c7f3Sopenharmony_ci switch (retval) 288b815c7f3Sopenharmony_ci { case -EAGAIN : 289b815c7f3Sopenharmony_ci puts ("alsa_write_float: EAGAIN") ; 290b815c7f3Sopenharmony_ci continue ; 291b815c7f3Sopenharmony_ci break ; 292b815c7f3Sopenharmony_ci 293b815c7f3Sopenharmony_ci case -EPIPE : 294b815c7f3Sopenharmony_ci if (epipe_count > 0) 295b815c7f3Sopenharmony_ci { printf ("alsa_write_float: EPIPE %d\n", epipe_count) ; 296b815c7f3Sopenharmony_ci if (epipe_count > 140) 297b815c7f3Sopenharmony_ci return retval ; 298b815c7f3Sopenharmony_ci } ; 299b815c7f3Sopenharmony_ci epipe_count += 100 ; 300b815c7f3Sopenharmony_ci 301b815c7f3Sopenharmony_ci#if 0 302b815c7f3Sopenharmony_ci if (0) 303b815c7f3Sopenharmony_ci { snd_pcm_status_t *status ; 304b815c7f3Sopenharmony_ci 305b815c7f3Sopenharmony_ci snd_pcm_status_alloca (&status) ; 306b815c7f3Sopenharmony_ci if ((retval = snd_pcm_status (alsa_dev, status)) < 0) 307b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_out: xrun. can't determine length\n") ; 308b815c7f3Sopenharmony_ci else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) 309b815c7f3Sopenharmony_ci { struct timeval now, diff, tstamp ; 310b815c7f3Sopenharmony_ci 311b815c7f3Sopenharmony_ci gettimeofday (&now, 0) ; 312b815c7f3Sopenharmony_ci snd_pcm_status_get_trigger_tstamp (status, &tstamp) ; 313b815c7f3Sopenharmony_ci timersub (&now, &tstamp, &diff) ; 314b815c7f3Sopenharmony_ci 315b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n", 316b815c7f3Sopenharmony_ci diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ; 317b815c7f3Sopenharmony_ci } 318b815c7f3Sopenharmony_ci else 319b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ; 320b815c7f3Sopenharmony_ci } ; 321b815c7f3Sopenharmony_ci#endif 322b815c7f3Sopenharmony_ci 323b815c7f3Sopenharmony_ci snd_pcm_prepare (alsa_dev) ; 324b815c7f3Sopenharmony_ci break ; 325b815c7f3Sopenharmony_ci 326b815c7f3Sopenharmony_ci case -EBADFD : 327b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_write_float: Bad PCM state.n") ; 328b815c7f3Sopenharmony_ci return 0 ; 329b815c7f3Sopenharmony_ci break ; 330b815c7f3Sopenharmony_ci 331b815c7f3Sopenharmony_ci#if defined ESTRPIPE && ESTRPIPE != EPIPE 332b815c7f3Sopenharmony_ci case -ESTRPIPE : 333b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_write_float: Suspend event.n") ; 334b815c7f3Sopenharmony_ci return 0 ; 335b815c7f3Sopenharmony_ci break ; 336b815c7f3Sopenharmony_ci#endif 337b815c7f3Sopenharmony_ci 338b815c7f3Sopenharmony_ci case -EIO : 339b815c7f3Sopenharmony_ci puts ("alsa_write_float: EIO") ; 340b815c7f3Sopenharmony_ci return 0 ; 341b815c7f3Sopenharmony_ci 342b815c7f3Sopenharmony_ci default : 343b815c7f3Sopenharmony_ci fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ; 344b815c7f3Sopenharmony_ci return 0 ; 345b815c7f3Sopenharmony_ci break ; 346b815c7f3Sopenharmony_ci } ; /* switch */ 347b815c7f3Sopenharmony_ci } ; /* while */ 348b815c7f3Sopenharmony_ci 349b815c7f3Sopenharmony_ci return total ; 350b815c7f3Sopenharmony_ci} /* alsa_write_float */ 351b815c7f3Sopenharmony_ci 352b815c7f3Sopenharmony_ci#endif /* HAVE_ALSA_ASOUNDLIB_H */ 353b815c7f3Sopenharmony_ci 354b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 355b815c7f3Sopenharmony_ci** Linux/OSS functions for playing a sound. 356b815c7f3Sopenharmony_ci*/ 357b815c7f3Sopenharmony_ci 358b815c7f3Sopenharmony_ci#if !defined (__ANDROID__) && (defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__)) 359b815c7f3Sopenharmony_ci 360b815c7f3Sopenharmony_cistatic int opensoundsys_open_device (int channels, int srate) ; 361b815c7f3Sopenharmony_ci 362b815c7f3Sopenharmony_cistatic int 363b815c7f3Sopenharmony_ciopensoundsys_play (int argc, char *argv []) 364b815c7f3Sopenharmony_ci{ static short buffer [BUFFER_LEN] ; 365b815c7f3Sopenharmony_ci SNDFILE *sndfile ; 366b815c7f3Sopenharmony_ci SF_INFO sfinfo ; 367b815c7f3Sopenharmony_ci int k, audio_device, readcount, writecount, subformat ; 368b815c7f3Sopenharmony_ci 369b815c7f3Sopenharmony_ci for (k = 1 ; k < argc ; k++) 370b815c7f3Sopenharmony_ci { memset (&sfinfo, 0, sizeof (sfinfo)) ; 371b815c7f3Sopenharmony_ci 372b815c7f3Sopenharmony_ci printf ("Playing %s\n", argv [k]) ; 373b815c7f3Sopenharmony_ci if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) 374b815c7f3Sopenharmony_ci { puts (sf_strerror (NULL)) ; 375b815c7f3Sopenharmony_ci continue ; 376b815c7f3Sopenharmony_ci } ; 377b815c7f3Sopenharmony_ci 378b815c7f3Sopenharmony_ci if (sfinfo.channels < 1 || sfinfo.channels > 2) 379b815c7f3Sopenharmony_ci { printf ("Error : channels = %d.\n", sfinfo.channels) ; 380b815c7f3Sopenharmony_ci continue ; 381b815c7f3Sopenharmony_ci } ; 382b815c7f3Sopenharmony_ci 383b815c7f3Sopenharmony_ci audio_device = opensoundsys_open_device (sfinfo.channels, sfinfo.samplerate) ; 384b815c7f3Sopenharmony_ci 385b815c7f3Sopenharmony_ci subformat = sfinfo.format & SF_FORMAT_SUBMASK ; 386b815c7f3Sopenharmony_ci 387b815c7f3Sopenharmony_ci if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) 388b815c7f3Sopenharmony_ci { static float float_buffer [BUFFER_LEN] ; 389b815c7f3Sopenharmony_ci double scale ; 390b815c7f3Sopenharmony_ci int m ; 391b815c7f3Sopenharmony_ci 392b815c7f3Sopenharmony_ci sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; 393b815c7f3Sopenharmony_ci if (scale < 1e-10) 394b815c7f3Sopenharmony_ci scale = 1.0 ; 395b815c7f3Sopenharmony_ci else 396b815c7f3Sopenharmony_ci scale = 32700.0 / scale ; 397b815c7f3Sopenharmony_ci 398b815c7f3Sopenharmony_ci while ((readcount = sf_read_float (sndfile, float_buffer, BUFFER_LEN))) 399b815c7f3Sopenharmony_ci { for (m = 0 ; m < readcount ; m++) 400b815c7f3Sopenharmony_ci buffer [m] = scale * float_buffer [m] ; 401b815c7f3Sopenharmony_ci writecount = write (audio_device, buffer, readcount * sizeof (short)) ; 402b815c7f3Sopenharmony_ci } ; 403b815c7f3Sopenharmony_ci } 404b815c7f3Sopenharmony_ci else 405b815c7f3Sopenharmony_ci { while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN))) 406b815c7f3Sopenharmony_ci writecount = write (audio_device, buffer, readcount * sizeof (short)) ; 407b815c7f3Sopenharmony_ci } ; 408b815c7f3Sopenharmony_ci 409b815c7f3Sopenharmony_ci if (ioctl (audio_device, SNDCTL_DSP_POST, 0) == -1) 410b815c7f3Sopenharmony_ci perror ("ioctl (SNDCTL_DSP_POST) ") ; 411b815c7f3Sopenharmony_ci 412b815c7f3Sopenharmony_ci if (ioctl (audio_device, SNDCTL_DSP_SYNC, 0) == -1) 413b815c7f3Sopenharmony_ci perror ("ioctl (SNDCTL_DSP_SYNC) ") ; 414b815c7f3Sopenharmony_ci 415b815c7f3Sopenharmony_ci close (audio_device) ; 416b815c7f3Sopenharmony_ci 417b815c7f3Sopenharmony_ci sf_close (sndfile) ; 418b815c7f3Sopenharmony_ci } ; 419b815c7f3Sopenharmony_ci 420b815c7f3Sopenharmony_ci return writecount ; 421b815c7f3Sopenharmony_ci} /* opensoundsys_play */ 422b815c7f3Sopenharmony_ci 423b815c7f3Sopenharmony_cistatic int 424b815c7f3Sopenharmony_ciopensoundsys_open_device (int channels, int srate) 425b815c7f3Sopenharmony_ci{ int fd, stereo, fmt ; 426b815c7f3Sopenharmony_ci 427b815c7f3Sopenharmony_ci if ((fd = open ("/dev/dsp", O_WRONLY, 0)) == -1 && 428b815c7f3Sopenharmony_ci (fd = open ("/dev/sound/dsp", O_WRONLY, 0)) == -1) 429b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : open ") ; 430b815c7f3Sopenharmony_ci exit (1) ; 431b815c7f3Sopenharmony_ci } ; 432b815c7f3Sopenharmony_ci 433b815c7f3Sopenharmony_ci stereo = 0 ; 434b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1) 435b815c7f3Sopenharmony_ci { /* Fatal error */ 436b815c7f3Sopenharmony_ci perror ("opensoundsys_open_device : stereo ") ; 437b815c7f3Sopenharmony_ci exit (1) ; 438b815c7f3Sopenharmony_ci } ; 439b815c7f3Sopenharmony_ci 440b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_RESET, 0)) 441b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : reset ") ; 442b815c7f3Sopenharmony_ci exit (1) ; 443b815c7f3Sopenharmony_ci } ; 444b815c7f3Sopenharmony_ci 445b815c7f3Sopenharmony_ci fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ; 446b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) != 0) 447b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : set format ") ; 448b815c7f3Sopenharmony_ci exit (1) ; 449b815c7f3Sopenharmony_ci } ; 450b815c7f3Sopenharmony_ci 451b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) != 0) 452b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : channels ") ; 453b815c7f3Sopenharmony_ci exit (1) ; 454b815c7f3Sopenharmony_ci } ; 455b815c7f3Sopenharmony_ci 456b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_SPEED, &srate) != 0) 457b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : sample rate ") ; 458b815c7f3Sopenharmony_ci exit (1) ; 459b815c7f3Sopenharmony_ci } ; 460b815c7f3Sopenharmony_ci 461b815c7f3Sopenharmony_ci if (ioctl (fd, SNDCTL_DSP_SYNC, 0) != 0) 462b815c7f3Sopenharmony_ci { perror ("opensoundsys_open_device : sync ") ; 463b815c7f3Sopenharmony_ci exit (1) ; 464b815c7f3Sopenharmony_ci } ; 465b815c7f3Sopenharmony_ci 466b815c7f3Sopenharmony_ci return fd ; 467b815c7f3Sopenharmony_ci} /* opensoundsys_open_device */ 468b815c7f3Sopenharmony_ci 469b815c7f3Sopenharmony_ci#endif /* __linux__ */ 470b815c7f3Sopenharmony_ci 471b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 472b815c7f3Sopenharmony_ci** Mac OS X functions for playing a sound. 473b815c7f3Sopenharmony_ci*/ 474b815c7f3Sopenharmony_ci 475b815c7f3Sopenharmony_ci/* MacOSX 10.8 use a new Audio API. Someone needs to write some code for it. */ 476b815c7f3Sopenharmony_ci 477b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 478b815c7f3Sopenharmony_ci** Win32 functions for playing a sound. 479b815c7f3Sopenharmony_ci** 480b815c7f3Sopenharmony_ci** This API sucks. Its needlessly complicated and is *WAY* too loose with 481b815c7f3Sopenharmony_ci** passing pointers around in integers and using char* pointers to 482b815c7f3Sopenharmony_ci** point to data instead of short*. It plain sucks! 483b815c7f3Sopenharmony_ci*/ 484b815c7f3Sopenharmony_ci 485b815c7f3Sopenharmony_ci#if (OS_IS_WIN32 == 1) 486b815c7f3Sopenharmony_ci 487b815c7f3Sopenharmony_ci#define WIN32_BUFFER_LEN (1 << 15) 488b815c7f3Sopenharmony_ci 489b815c7f3Sopenharmony_citypedef struct 490b815c7f3Sopenharmony_ci{ HWAVEOUT hwave ; 491b815c7f3Sopenharmony_ci WAVEHDR whdr [2] ; 492b815c7f3Sopenharmony_ci 493b815c7f3Sopenharmony_ci CRITICAL_SECTION mutex ; /* to control access to BuffersInUSe */ 494b815c7f3Sopenharmony_ci HANDLE Event ; /* signal that a buffer is free */ 495b815c7f3Sopenharmony_ci 496b815c7f3Sopenharmony_ci short buffer [WIN32_BUFFER_LEN / sizeof (short)] ; 497b815c7f3Sopenharmony_ci int current, bufferlen ; 498b815c7f3Sopenharmony_ci int BuffersInUse ; 499b815c7f3Sopenharmony_ci 500b815c7f3Sopenharmony_ci SNDFILE *sndfile ; 501b815c7f3Sopenharmony_ci SF_INFO sfinfo ; 502b815c7f3Sopenharmony_ci 503b815c7f3Sopenharmony_ci sf_count_t remaining ; 504b815c7f3Sopenharmony_ci} Win32_Audio_Data ; 505b815c7f3Sopenharmony_ci 506b815c7f3Sopenharmony_ci 507b815c7f3Sopenharmony_cistatic void 508b815c7f3Sopenharmony_ciwin32_play_data (Win32_Audio_Data *audio_data) 509b815c7f3Sopenharmony_ci{ int thisread, readcount ; 510b815c7f3Sopenharmony_ci 511b815c7f3Sopenharmony_ci /* fill a buffer if there is more data and we can read it sucessfully */ 512b815c7f3Sopenharmony_ci readcount = (audio_data->remaining > audio_data->bufferlen) ? audio_data->bufferlen : (int) audio_data->remaining ; 513b815c7f3Sopenharmony_ci 514b815c7f3Sopenharmony_ci short *lpData = (short *) (void *) audio_data->whdr [audio_data->current].lpData ; 515b815c7f3Sopenharmony_ci thisread = (int) sf_read_short (audio_data->sndfile, lpData, readcount) ; 516b815c7f3Sopenharmony_ci 517b815c7f3Sopenharmony_ci audio_data->remaining -= thisread ; 518b815c7f3Sopenharmony_ci 519b815c7f3Sopenharmony_ci if (thisread > 0) 520b815c7f3Sopenharmony_ci { /* Fix buffer length if this is only a partial block. */ 521b815c7f3Sopenharmony_ci if (thisread < audio_data->bufferlen) 522b815c7f3Sopenharmony_ci audio_data->whdr [audio_data->current].dwBufferLength = thisread * sizeof (short) ; 523b815c7f3Sopenharmony_ci 524b815c7f3Sopenharmony_ci /* Queue the WAVEHDR */ 525b815c7f3Sopenharmony_ci waveOutWrite (audio_data->hwave, (LPWAVEHDR) &(audio_data->whdr [audio_data->current]), sizeof (WAVEHDR)) ; 526b815c7f3Sopenharmony_ci 527b815c7f3Sopenharmony_ci /* count another buffer in use */ 528b815c7f3Sopenharmony_ci EnterCriticalSection (&audio_data->mutex) ; 529b815c7f3Sopenharmony_ci audio_data->BuffersInUse ++ ; 530b815c7f3Sopenharmony_ci LeaveCriticalSection (&audio_data->mutex) ; 531b815c7f3Sopenharmony_ci 532b815c7f3Sopenharmony_ci /* use the other buffer next time */ 533b815c7f3Sopenharmony_ci audio_data->current = (audio_data->current + 1) % 2 ; 534b815c7f3Sopenharmony_ci } ; 535b815c7f3Sopenharmony_ci 536b815c7f3Sopenharmony_ci return ; 537b815c7f3Sopenharmony_ci} /* win32_play_data */ 538b815c7f3Sopenharmony_ci 539b815c7f3Sopenharmony_cistatic void CALLBACK 540b815c7f3Sopenharmony_ciwin32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD_PTR data, DWORD param1, DWORD param2) 541b815c7f3Sopenharmony_ci{ Win32_Audio_Data *audio_data ; 542b815c7f3Sopenharmony_ci 543b815c7f3Sopenharmony_ci /* Prevent compiler warnings. */ 544b815c7f3Sopenharmony_ci (void) hwave ; 545b815c7f3Sopenharmony_ci (void) param1 ; 546b815c7f3Sopenharmony_ci (void) param2 ; 547b815c7f3Sopenharmony_ci 548b815c7f3Sopenharmony_ci if (data == 0) 549b815c7f3Sopenharmony_ci return ; 550b815c7f3Sopenharmony_ci 551b815c7f3Sopenharmony_ci /* 552b815c7f3Sopenharmony_ci ** I consider this technique of passing a pointer via an integer as 553b815c7f3Sopenharmony_ci ** fundamentally broken but thats the way microsoft has defined the 554b815c7f3Sopenharmony_ci ** interface. 555b815c7f3Sopenharmony_ci */ 556b815c7f3Sopenharmony_ci audio_data = (Win32_Audio_Data*) data ; 557b815c7f3Sopenharmony_ci 558b815c7f3Sopenharmony_ci /* let main loop know a buffer is free */ 559b815c7f3Sopenharmony_ci if (msg == MM_WOM_DONE) 560b815c7f3Sopenharmony_ci { EnterCriticalSection (&audio_data->mutex) ; 561b815c7f3Sopenharmony_ci audio_data->BuffersInUse -- ; 562b815c7f3Sopenharmony_ci LeaveCriticalSection (&audio_data->mutex) ; 563b815c7f3Sopenharmony_ci SetEvent (audio_data->Event) ; 564b815c7f3Sopenharmony_ci } ; 565b815c7f3Sopenharmony_ci 566b815c7f3Sopenharmony_ci return ; 567b815c7f3Sopenharmony_ci} /* win32_audio_out_callback */ 568b815c7f3Sopenharmony_ci 569b815c7f3Sopenharmony_cistatic void 570b815c7f3Sopenharmony_ciwin32_play (int argc, char *argv []) 571b815c7f3Sopenharmony_ci{ Win32_Audio_Data audio_data ; 572b815c7f3Sopenharmony_ci 573b815c7f3Sopenharmony_ci WAVEFORMATEX wf ; 574b815c7f3Sopenharmony_ci int k, error ; 575b815c7f3Sopenharmony_ci 576b815c7f3Sopenharmony_ci audio_data.sndfile = NULL ; 577b815c7f3Sopenharmony_ci audio_data.hwave = 0 ; 578b815c7f3Sopenharmony_ci 579b815c7f3Sopenharmony_ci for (k = 1 ; k < argc ; k++) 580b815c7f3Sopenharmony_ci { printf ("Playing %s\n", argv [k]) ; 581b815c7f3Sopenharmony_ci 582b815c7f3Sopenharmony_ci if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo)))) 583b815c7f3Sopenharmony_ci { puts (sf_strerror (NULL)) ; 584b815c7f3Sopenharmony_ci continue ; 585b815c7f3Sopenharmony_ci } ; 586b815c7f3Sopenharmony_ci 587b815c7f3Sopenharmony_ci audio_data.remaining = audio_data.sfinfo.frames * audio_data.sfinfo.channels ; 588b815c7f3Sopenharmony_ci audio_data.current = 0 ; 589b815c7f3Sopenharmony_ci 590b815c7f3Sopenharmony_ci InitializeCriticalSection (&audio_data.mutex) ; 591b815c7f3Sopenharmony_ci audio_data.Event = CreateEvent (0, FALSE, FALSE, 0) ; 592b815c7f3Sopenharmony_ci 593b815c7f3Sopenharmony_ci wf.nChannels = audio_data.sfinfo.channels ; 594b815c7f3Sopenharmony_ci wf.wFormatTag = WAVE_FORMAT_PCM ; 595b815c7f3Sopenharmony_ci wf.cbSize = 0 ; 596b815c7f3Sopenharmony_ci wf.wBitsPerSample = 16 ; 597b815c7f3Sopenharmony_ci 598b815c7f3Sopenharmony_ci wf.nSamplesPerSec = audio_data.sfinfo.samplerate ; 599b815c7f3Sopenharmony_ci 600b815c7f3Sopenharmony_ci wf.nBlockAlign = audio_data.sfinfo.channels * sizeof (short) ; 601b815c7f3Sopenharmony_ci 602b815c7f3Sopenharmony_ci wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ; 603b815c7f3Sopenharmony_ci 604b815c7f3Sopenharmony_ci error = waveOutOpen (&(audio_data.hwave), WAVE_MAPPER, &wf, (DWORD_PTR) win32_audio_out_callback, 605b815c7f3Sopenharmony_ci (DWORD_PTR) &audio_data, CALLBACK_FUNCTION) ; 606b815c7f3Sopenharmony_ci if (error) 607b815c7f3Sopenharmony_ci { puts ("waveOutOpen failed.") ; 608b815c7f3Sopenharmony_ci audio_data.hwave = 0 ; 609b815c7f3Sopenharmony_ci continue ; 610b815c7f3Sopenharmony_ci } ; 611b815c7f3Sopenharmony_ci 612b815c7f3Sopenharmony_ci audio_data.whdr [0].lpData = (char*) audio_data.buffer ; 613b815c7f3Sopenharmony_ci audio_data.whdr [1].lpData = ((char*) audio_data.buffer) + sizeof (audio_data.buffer) / 2 ; 614b815c7f3Sopenharmony_ci 615b815c7f3Sopenharmony_ci audio_data.whdr [0].dwBufferLength = sizeof (audio_data.buffer) / 2 ; 616b815c7f3Sopenharmony_ci audio_data.whdr [1].dwBufferLength = sizeof (audio_data.buffer) / 2 ; 617b815c7f3Sopenharmony_ci 618b815c7f3Sopenharmony_ci audio_data.whdr [0].dwFlags = 0 ; 619b815c7f3Sopenharmony_ci audio_data.whdr [1].dwFlags = 0 ; 620b815c7f3Sopenharmony_ci 621b815c7f3Sopenharmony_ci /* length of each audio buffer in samples */ 622b815c7f3Sopenharmony_ci audio_data.bufferlen = sizeof (audio_data.buffer) / 2 / sizeof (short) ; 623b815c7f3Sopenharmony_ci 624b815c7f3Sopenharmony_ci /* Prepare the WAVEHDRs */ 625b815c7f3Sopenharmony_ci if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)))) 626b815c7f3Sopenharmony_ci { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ; 627b815c7f3Sopenharmony_ci waveOutClose (audio_data.hwave) ; 628b815c7f3Sopenharmony_ci continue ; 629b815c7f3Sopenharmony_ci } ; 630b815c7f3Sopenharmony_ci 631b815c7f3Sopenharmony_ci if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)))) 632b815c7f3Sopenharmony_ci { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ; 633b815c7f3Sopenharmony_ci waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; 634b815c7f3Sopenharmony_ci waveOutClose (audio_data.hwave) ; 635b815c7f3Sopenharmony_ci continue ; 636b815c7f3Sopenharmony_ci } ; 637b815c7f3Sopenharmony_ci 638b815c7f3Sopenharmony_ci /* Fill up both buffers with audio data */ 639b815c7f3Sopenharmony_ci audio_data.BuffersInUse = 0 ; 640b815c7f3Sopenharmony_ci win32_play_data (&audio_data) ; 641b815c7f3Sopenharmony_ci win32_play_data (&audio_data) ; 642b815c7f3Sopenharmony_ci 643b815c7f3Sopenharmony_ci /* loop until both buffers are released */ 644b815c7f3Sopenharmony_ci while (audio_data.BuffersInUse > 0) 645b815c7f3Sopenharmony_ci { 646b815c7f3Sopenharmony_ci /* wait for buffer to be released */ 647b815c7f3Sopenharmony_ci WaitForSingleObject (audio_data.Event, INFINITE) ; 648b815c7f3Sopenharmony_ci 649b815c7f3Sopenharmony_ci /* refill the buffer if there is more data to play */ 650b815c7f3Sopenharmony_ci win32_play_data (&audio_data) ; 651b815c7f3Sopenharmony_ci } ; 652b815c7f3Sopenharmony_ci 653b815c7f3Sopenharmony_ci waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; 654b815c7f3Sopenharmony_ci waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)) ; 655b815c7f3Sopenharmony_ci 656b815c7f3Sopenharmony_ci waveOutClose (audio_data.hwave) ; 657b815c7f3Sopenharmony_ci audio_data.hwave = 0 ; 658b815c7f3Sopenharmony_ci 659b815c7f3Sopenharmony_ci DeleteCriticalSection (&audio_data.mutex) ; 660b815c7f3Sopenharmony_ci 661b815c7f3Sopenharmony_ci sf_close (audio_data.sndfile) ; 662b815c7f3Sopenharmony_ci } ; 663b815c7f3Sopenharmony_ci 664b815c7f3Sopenharmony_ci} /* win32_play */ 665b815c7f3Sopenharmony_ci 666b815c7f3Sopenharmony_ci#endif /* Win32 */ 667b815c7f3Sopenharmony_ci 668b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 669b815c7f3Sopenharmony_ci** OpenBSD's sndio. 670b815c7f3Sopenharmony_ci*/ 671b815c7f3Sopenharmony_ci 672b815c7f3Sopenharmony_ci#if HAVE_SNDIO_H 673b815c7f3Sopenharmony_ci 674b815c7f3Sopenharmony_cistatic void 675b815c7f3Sopenharmony_cisndio_play (int argc, char *argv []) 676b815c7f3Sopenharmony_ci{ struct sio_hdl *hdl ; 677b815c7f3Sopenharmony_ci struct sio_par par ; 678b815c7f3Sopenharmony_ci short buffer [BUFFER_LEN] ; 679b815c7f3Sopenharmony_ci SNDFILE *sndfile ; 680b815c7f3Sopenharmony_ci SF_INFO sfinfo ; 681b815c7f3Sopenharmony_ci int k, readcount ; 682b815c7f3Sopenharmony_ci 683b815c7f3Sopenharmony_ci for (k = 1 ; k < argc ; k++) 684b815c7f3Sopenharmony_ci { printf ("Playing %s\n", argv [k]) ; 685b815c7f3Sopenharmony_ci if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) 686b815c7f3Sopenharmony_ci { puts (sf_strerror (NULL)) ; 687b815c7f3Sopenharmony_ci continue ; 688b815c7f3Sopenharmony_ci } ; 689b815c7f3Sopenharmony_ci 690b815c7f3Sopenharmony_ci if (sfinfo.channels < 1 || sfinfo.channels > 2) 691b815c7f3Sopenharmony_ci { printf ("Error : channels = %d.\n", sfinfo.channels) ; 692b815c7f3Sopenharmony_ci continue ; 693b815c7f3Sopenharmony_ci } ; 694b815c7f3Sopenharmony_ci 695b815c7f3Sopenharmony_ci if ((hdl = sio_open (NULL, SIO_PLAY, 0)) == NULL) 696b815c7f3Sopenharmony_ci { fprintf (stderr, "open sndio device failed") ; 697b815c7f3Sopenharmony_ci return ; 698b815c7f3Sopenharmony_ci } ; 699b815c7f3Sopenharmony_ci 700b815c7f3Sopenharmony_ci sio_initpar (&par) ; 701b815c7f3Sopenharmony_ci par.rate = sfinfo.samplerate ; 702b815c7f3Sopenharmony_ci par.pchan = sfinfo.channels ; 703b815c7f3Sopenharmony_ci par.bits = 16 ; 704b815c7f3Sopenharmony_ci par.sig = 1 ; 705b815c7f3Sopenharmony_ci par.le = SIO_LE_NATIVE ; 706b815c7f3Sopenharmony_ci 707b815c7f3Sopenharmony_ci if (! sio_setpar (hdl, &par) || ! sio_getpar (hdl, &par)) 708b815c7f3Sopenharmony_ci { fprintf (stderr, "set sndio params failed") ; 709b815c7f3Sopenharmony_ci return ; 710b815c7f3Sopenharmony_ci } ; 711b815c7f3Sopenharmony_ci 712b815c7f3Sopenharmony_ci if (! sio_start (hdl)) 713b815c7f3Sopenharmony_ci { fprintf (stderr, "sndio start failed") ; 714b815c7f3Sopenharmony_ci return ; 715b815c7f3Sopenharmony_ci } ; 716b815c7f3Sopenharmony_ci 717b815c7f3Sopenharmony_ci while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN))) 718b815c7f3Sopenharmony_ci sio_write (hdl, buffer, readcount * sizeof (short)) ; 719b815c7f3Sopenharmony_ci 720b815c7f3Sopenharmony_ci sio_close (hdl) ; 721b815c7f3Sopenharmony_ci } ; 722b815c7f3Sopenharmony_ci 723b815c7f3Sopenharmony_ci return ; 724b815c7f3Sopenharmony_ci} /* sndio_play */ 725b815c7f3Sopenharmony_ci 726b815c7f3Sopenharmony_ci#endif /* sndio */ 727b815c7f3Sopenharmony_ci 728b815c7f3Sopenharmony_ci/*------------------------------------------------------------------------------ 729b815c7f3Sopenharmony_ci** Solaris. 730b815c7f3Sopenharmony_ci*/ 731b815c7f3Sopenharmony_ci 732b815c7f3Sopenharmony_ci#if (defined (sun) && defined (unix)) || defined(__NetBSD__) 733b815c7f3Sopenharmony_ci 734b815c7f3Sopenharmony_cistatic void 735b815c7f3Sopenharmony_cisolaris_play (int argc, char *argv []) 736b815c7f3Sopenharmony_ci{ static short buffer [BUFFER_LEN] ; 737b815c7f3Sopenharmony_ci audio_info_t audio_info ; 738b815c7f3Sopenharmony_ci SNDFILE *sndfile ; 739b815c7f3Sopenharmony_ci SF_INFO sfinfo ; 740b815c7f3Sopenharmony_ci unsigned long delay_time ; 741b815c7f3Sopenharmony_ci long k, start_count, output_count, write_count, read_count ; 742b815c7f3Sopenharmony_ci int audio_fd, error, done ; 743b815c7f3Sopenharmony_ci 744b815c7f3Sopenharmony_ci for (k = 1 ; k < argc ; k++) 745b815c7f3Sopenharmony_ci { printf ("Playing %s\n", argv [k]) ; 746b815c7f3Sopenharmony_ci if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) 747b815c7f3Sopenharmony_ci { puts (sf_strerror (NULL)) ; 748b815c7f3Sopenharmony_ci continue ; 749b815c7f3Sopenharmony_ci } ; 750b815c7f3Sopenharmony_ci 751b815c7f3Sopenharmony_ci if (sfinfo.channels < 1 || sfinfo.channels > 2) 752b815c7f3Sopenharmony_ci { printf ("Error : channels = %d.\n", sfinfo.channels) ; 753b815c7f3Sopenharmony_ci continue ; 754b815c7f3Sopenharmony_ci } ; 755b815c7f3Sopenharmony_ci 756b815c7f3Sopenharmony_ci /* open the audio device - write only, non-blocking */ 757b815c7f3Sopenharmony_ci if ((audio_fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0) 758b815c7f3Sopenharmony_ci { perror ("open (/dev/audio) failed") ; 759b815c7f3Sopenharmony_ci return ; 760b815c7f3Sopenharmony_ci } ; 761b815c7f3Sopenharmony_ci 762b815c7f3Sopenharmony_ci /* Retrive standard values. */ 763b815c7f3Sopenharmony_ci AUDIO_INITINFO (&audio_info) ; 764b815c7f3Sopenharmony_ci 765b815c7f3Sopenharmony_ci audio_info.play.sample_rate = sfinfo.samplerate ; 766b815c7f3Sopenharmony_ci audio_info.play.channels = sfinfo.channels ; 767b815c7f3Sopenharmony_ci audio_info.play.precision = 16 ; 768b815c7f3Sopenharmony_ci audio_info.play.encoding = AUDIO_ENCODING_LINEAR ; 769b815c7f3Sopenharmony_ci 770b815c7f3Sopenharmony_ci if ((error = ioctl (audio_fd, AUDIO_SETINFO, &audio_info))) 771b815c7f3Sopenharmony_ci { perror ("ioctl (AUDIO_SETINFO) failed") ; 772b815c7f3Sopenharmony_ci return ; 773b815c7f3Sopenharmony_ci } ; 774b815c7f3Sopenharmony_ci 775b815c7f3Sopenharmony_ci /* Delay time equal to 1/4 of a buffer in microseconds. */ 776b815c7f3Sopenharmony_ci delay_time = (BUFFER_LEN * 1000000) / (audio_info.play.sample_rate * 4) ; 777b815c7f3Sopenharmony_ci 778b815c7f3Sopenharmony_ci done = 0 ; 779b815c7f3Sopenharmony_ci while (! done) 780b815c7f3Sopenharmony_ci { read_count = sf_read_short (sndfile, buffer, BUFFER_LEN) ; 781b815c7f3Sopenharmony_ci if (read_count < BUFFER_LEN) 782b815c7f3Sopenharmony_ci { memset (&(buffer [read_count]), 0, (BUFFER_LEN - read_count) * sizeof (short)) ; 783b815c7f3Sopenharmony_ci /* Tell the main application to terminate. */ 784b815c7f3Sopenharmony_ci done = SF_TRUE ; 785b815c7f3Sopenharmony_ci } ; 786b815c7f3Sopenharmony_ci 787b815c7f3Sopenharmony_ci start_count = 0 ; 788b815c7f3Sopenharmony_ci output_count = BUFFER_LEN * sizeof (short) ; 789b815c7f3Sopenharmony_ci 790b815c7f3Sopenharmony_ci while (output_count > 0) 791b815c7f3Sopenharmony_ci { /* write as much data as possible */ 792b815c7f3Sopenharmony_ci write_count = write (audio_fd, &(buffer [start_count]), output_count) ; 793b815c7f3Sopenharmony_ci if (write_count > 0) 794b815c7f3Sopenharmony_ci { output_count -= write_count ; 795b815c7f3Sopenharmony_ci start_count += write_count ; 796b815c7f3Sopenharmony_ci } 797b815c7f3Sopenharmony_ci else 798b815c7f3Sopenharmony_ci { /* Give the audio output time to catch up. */ 799b815c7f3Sopenharmony_ci usleep (delay_time) ; 800b815c7f3Sopenharmony_ci } ; 801b815c7f3Sopenharmony_ci } ; /* while (outpur_count > 0) */ 802b815c7f3Sopenharmony_ci } ; /* while (! done) */ 803b815c7f3Sopenharmony_ci 804b815c7f3Sopenharmony_ci close (audio_fd) ; 805b815c7f3Sopenharmony_ci } ; 806b815c7f3Sopenharmony_ci 807b815c7f3Sopenharmony_ci return ; 808b815c7f3Sopenharmony_ci} /* solaris_play */ 809b815c7f3Sopenharmony_ci 810b815c7f3Sopenharmony_ci#endif /* Solaris or NetBSD */ 811b815c7f3Sopenharmony_ci 812b815c7f3Sopenharmony_ci/*============================================================================== 813b815c7f3Sopenharmony_ci** Main function. 814b815c7f3Sopenharmony_ci*/ 815b815c7f3Sopenharmony_ci 816b815c7f3Sopenharmony_ciint 817b815c7f3Sopenharmony_cimain (int argc, char *argv []) 818b815c7f3Sopenharmony_ci{ 819b815c7f3Sopenharmony_ci if (argc < 2) 820b815c7f3Sopenharmony_ci { 821b815c7f3Sopenharmony_ci printf ("\nUsage : %s <input sound file>\n\n", program_name (argv [0])) ; 822b815c7f3Sopenharmony_ci printf ("Using %s.\n\n", sf_version_string ()) ; 823b815c7f3Sopenharmony_ci#if (OS_IS_WIN32 == 1) 824b815c7f3Sopenharmony_ci printf ("This is a Unix style command line application which\n" 825b815c7f3Sopenharmony_ci "should be run in a MSDOS box or Command Shell window.\n\n") ; 826b815c7f3Sopenharmony_ci printf ("Sleeping for 5 seconds before exiting.\n\n") ; 827b815c7f3Sopenharmony_ci 828b815c7f3Sopenharmony_ci Sleep (5 * 1000) ; 829b815c7f3Sopenharmony_ci#endif 830b815c7f3Sopenharmony_ci return 1 ; 831b815c7f3Sopenharmony_ci } ; 832b815c7f3Sopenharmony_ci 833b815c7f3Sopenharmony_ci#if defined (__ANDROID__) 834b815c7f3Sopenharmony_ci puts ("*** Playing sound not yet supported on Android.") ; 835b815c7f3Sopenharmony_ci puts ("*** Please feel free to submit a patch.") ; 836b815c7f3Sopenharmony_ci return 1 ; 837b815c7f3Sopenharmony_ci#elif defined (__linux__) 838b815c7f3Sopenharmony_ci #if HAVE_ALSA_ASOUNDLIB_H 839b815c7f3Sopenharmony_ci if (access ("/proc/asound/cards", R_OK) == 0) 840b815c7f3Sopenharmony_ci alsa_play (argc, argv) ; 841b815c7f3Sopenharmony_ci else 842b815c7f3Sopenharmony_ci #endif 843b815c7f3Sopenharmony_ci opensoundsys_play (argc, argv) ; 844b815c7f3Sopenharmony_ci#elif defined (__FreeBSD_kernel__) || defined (__FreeBSD__) 845b815c7f3Sopenharmony_ci opensoundsys_play (argc, argv) ; 846b815c7f3Sopenharmony_ci#elif HAVE_SNDIO_H 847b815c7f3Sopenharmony_ci sndio_play (argc, argv) ; 848b815c7f3Sopenharmony_ci#elif (defined (sun) && defined (unix)) || defined(__NetBSD__) 849b815c7f3Sopenharmony_ci solaris_play (argc, argv) ; 850b815c7f3Sopenharmony_ci#elif (OS_IS_WIN32 == 1) 851b815c7f3Sopenharmony_ci win32_play (argc, argv) ; 852b815c7f3Sopenharmony_ci#else 853b815c7f3Sopenharmony_ci puts ("*** Playing sound not supported on this platform.") ; 854b815c7f3Sopenharmony_ci puts ("*** Please feel free to submit a patch.") ; 855b815c7f3Sopenharmony_ci return 1 ; 856b815c7f3Sopenharmony_ci#endif 857b815c7f3Sopenharmony_ci 858b815c7f3Sopenharmony_ci return 0 ; 859b815c7f3Sopenharmony_ci} /* main */ 860b815c7f3Sopenharmony_ci 861