"Fossies" - the Fresh Open Source Software Archive

Member "audacious-plugins-3.10.1/src/sndio/sndio.cc" (26 Dec 2018, 8494 Bytes) of package /linux/misc/audacious-plugins-3.10.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sndio.cc" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Sndio Output Plugin for Audacious
    3  * Copyright 2014 John Lindgren
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions, and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright notice,
   12  *    this list of conditions, and the following disclaimer in the documentation
   13  *    provided with the distribution.
   14  *
   15  * This software is provided "as is" and without any warranty, express or
   16  * implied. In no event shall the authors be liable for any damages arising from
   17  * the use of this software.
   18  */
   19 
   20 #include <libaudcore/audstrings.h>
   21 #include <libaudcore/i18n.h>
   22 #include <libaudcore/plugin.h>
   23 #include <libaudcore/preferences.h>
   24 #include <libaudcore/runtime.h>
   25 
   26 #include <errno.h>
   27 #include <poll.h>
   28 #include <pthread.h>
   29 #include <string.h>
   30 #include <sys/time.h>
   31 #include <time.h>
   32 
   33 #include <sndio.h>
   34 
   35 class SndioPlugin : public OutputPlugin
   36 {
   37 public:
   38     static const char * const defaults[];
   39     static const PreferencesWidget widgets[];
   40     static const PluginPreferences prefs;
   41 
   42     static constexpr PluginInfo info = {
   43         N_("Sndio Output"),
   44         PACKAGE,
   45         nullptr,
   46         & prefs
   47     };
   48 
   49     constexpr SndioPlugin () : OutputPlugin (info, 5) {}
   50 
   51     bool init ();
   52 
   53     StereoVolume get_volume ();
   54     void set_volume (StereoVolume v);
   55 
   56     bool open_audio (int format, int rate, int channels, String & error);
   57     void close_audio ();
   58 
   59     void period_wait ();
   60     int write_audio (const void * data, int size);
   61     void drain ();
   62 
   63     int get_delay ();
   64 
   65     void flush ();
   66 
   67     // not implemented
   68     void pause (bool pause) {}
   69 
   70 private:
   71     bool poll_locked ();
   72 
   73     static void volume_cb (void *, unsigned int vol);
   74     static void move_cb (void * arg, int delta);
   75 
   76     sio_hdl * m_handle = nullptr;
   77 
   78     int m_rate = 0, m_channels = 0;
   79     int m_bytes_per_frame = 0;
   80 
   81     int m_frames_buffered = 0;
   82     timeval m_last_write_time = timeval ();
   83     int m_flush_count = 0;
   84 
   85     pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
   86     pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
   87 };
   88 
   89 EXPORT SndioPlugin aud_plugin_instance;
   90 
   91 const char * const SndioPlugin::defaults[] = {
   92     "save_volume", "FALSE",
   93     "volume", "100",
   94     nullptr
   95 };
   96 
   97 const PreferencesWidget SndioPlugin::widgets[] = {
   98     WidgetEntry (N_("Device (blank for default):"),
   99         WidgetString ("sndio", "device")),
  100     WidgetCheck (N_("Save and restore volume:"),
  101         WidgetBool ("sndio", "save_volume"))
  102 };
  103 
  104 const PluginPreferences SndioPlugin::prefs = {{widgets}};
  105 
  106 bool SndioPlugin::init ()
  107 {
  108     aud_config_set_defaults ("sndio", defaults);
  109     return true;
  110 }
  111 
  112 void SndioPlugin::volume_cb (void *, unsigned int vol)
  113 {
  114     aud_set_int ("sndio", "volume", aud::rescale ((int) vol, SIO_MAXVOL, 100));
  115 }
  116 
  117 void SndioPlugin::set_volume (StereoVolume v)
  118 {
  119     int vol = aud::max (v.left, v.right);
  120     aud_set_int ("sndio", "volume", vol);
  121 
  122     pthread_mutex_lock (& m_mutex);
  123 
  124     if (m_handle)
  125         sio_setvol (m_handle, aud::rescale (vol, 100, SIO_MAXVOL));
  126 
  127     pthread_mutex_unlock (& m_mutex);
  128 }
  129 
  130 StereoVolume SndioPlugin::get_volume ()
  131 {
  132     int vol = aud_get_int ("sndio", "volume");
  133     return {vol, vol};
  134 }
  135 
  136 void SndioPlugin::move_cb (void * arg, int delta)
  137 {
  138     auto me = (SndioPlugin *) arg;
  139 
  140     me->m_frames_buffered -= delta;
  141     gettimeofday (& me->m_last_write_time, nullptr);
  142 
  143     pthread_cond_broadcast (& me->m_cond);
  144 }
  145 
  146 struct FormatData {
  147     int format;
  148     int bits, bytes;
  149     bool sign, le;
  150 };
  151 
  152 static const FormatData format_table[] = {
  153     {FMT_S8, 8, 1, true, false},
  154     {FMT_U8, 8, 1, false, false},
  155     {FMT_S16_LE, 16, 2, true, true},
  156     {FMT_S16_BE, 16, 2, true, false},
  157     {FMT_U16_LE, 16, 2, false, true},
  158     {FMT_U16_BE, 16, 2, false, false},
  159     {FMT_S24_LE, 24, 4, true, true},
  160     {FMT_S24_BE, 24, 4, true, false},
  161     {FMT_U24_LE, 24, 4, false, true},
  162     {FMT_U24_BE, 24, 4, false, false},
  163     {FMT_S32_LE, 32, 4, true, true},
  164     {FMT_S32_BE, 32, 4, true, false},
  165     {FMT_U32_LE, 32, 4, false, true},
  166     {FMT_U32_BE, 32, 4, false, false},
  167 };
  168 
  169 bool SndioPlugin::open_audio (int format, int rate, int channels, String & error)
  170 {
  171     const FormatData * fdata = nullptr;
  172 
  173     for (const FormatData & f : format_table)
  174     {
  175         if (f.format == format)
  176             fdata = & f;
  177     }
  178 
  179     if (! fdata)
  180     {
  181         error = String (str_printf (_("Sndio error: Unsupported audio format (%d)"), format));
  182         return false;
  183     }
  184 
  185     String device = aud_get_str ("sndio", "device");
  186     const char * device2 = device[0] ? (const char *) device : SIO_DEVANY;
  187 
  188     m_handle = sio_open (device2, SIO_PLAY, true);
  189 
  190     if (! m_handle)
  191     {
  192         error = String (_("Sndio error: sio_open() failed"));
  193         return false;
  194     }
  195 
  196     m_rate = rate;
  197     m_channels = channels;
  198     m_bytes_per_frame = FMT_SIZEOF (format) * channels;
  199 
  200     m_frames_buffered = 0;
  201     m_last_write_time = timeval ();
  202     m_flush_count = 0;
  203 
  204     int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
  205 
  206     sio_par par;
  207     sio_initpar (& par);
  208 
  209     par.bits = fdata->bits;
  210     par.bps = fdata->bytes;
  211     par.sig = fdata->sign;
  212     par.le = fdata->le;
  213     par.msb = false;
  214     par.pchan = channels;
  215     par.rate = rate;
  216     par.bufsz = aud::rescale (buffer_ms, 1000, rate);
  217     par.xrun = SIO_IGNORE;
  218 
  219     if (! sio_setpar (m_handle, & par))
  220     {
  221         error = String (_("Sndio error: sio_setpar() failed"));
  222         goto fail;
  223     }
  224 
  225     if (aud_get_bool ("sndio", "save_volume"))
  226         set_volume (get_volume ());
  227 
  228     sio_onvol (m_handle, volume_cb, nullptr);
  229     sio_onmove (m_handle, move_cb, this);
  230 
  231     if (! sio_start (m_handle))
  232     {
  233         error = String (_("Sndio error: sio_start() failed"));
  234         goto fail;
  235     }
  236 
  237     return true;
  238 
  239 fail:
  240     sio_close (m_handle);
  241     m_handle = nullptr;
  242     return false;
  243 }
  244 
  245 void SndioPlugin::close_audio ()
  246 {
  247     sio_close (m_handle);
  248     m_handle = nullptr;
  249 }
  250 
  251 bool SndioPlugin::poll_locked ()
  252 {
  253     bool success = false;
  254     pollfd * fds = nullptr;
  255     int nfds, old_flush_count;
  256 
  257     nfds = sio_nfds (m_handle);
  258     if (nfds < 1)
  259         goto fail;
  260 
  261     fds = new pollfd[nfds];
  262 
  263     nfds = sio_pollfd (m_handle, fds, POLLOUT);
  264     if (nfds < 1)
  265         goto fail;
  266 
  267     old_flush_count = m_flush_count;
  268 
  269     pthread_mutex_unlock (& m_mutex);
  270 
  271     if (poll (fds, nfds, -1) < 0)
  272         AUDERR ("poll() failed: %s\n", strerror (errno));
  273     else
  274         success = true;
  275 
  276     pthread_mutex_lock (& m_mutex);
  277 
  278     if (success && m_flush_count == old_flush_count)
  279         sio_revents (m_handle, fds);
  280 
  281 fail:
  282     delete[] fds;
  283     return success;
  284 }
  285 
  286 void SndioPlugin::period_wait ()
  287 {
  288     pthread_mutex_lock (& m_mutex);
  289 
  290     if (sio_eof (m_handle) || ! poll_locked ())
  291         pthread_cond_wait (& m_cond, & m_mutex);
  292 
  293     pthread_mutex_unlock (& m_mutex);
  294 }
  295 
  296 int SndioPlugin::write_audio (const void * data, int size)
  297 {
  298     pthread_mutex_lock (& m_mutex);
  299 
  300     int len = sio_write (m_handle, data, size);
  301     m_frames_buffered += len / m_bytes_per_frame;
  302 
  303     pthread_mutex_unlock (& m_mutex);
  304     return len;
  305 }
  306 
  307 void SndioPlugin::drain ()
  308 {
  309     pthread_mutex_lock (& m_mutex);
  310 
  311     int d = aud::rescale (m_frames_buffered, m_rate, 1000);
  312     timespec delay = {d / 1000, d % 1000 * 1000000};
  313 
  314     pthread_mutex_unlock (& m_mutex);
  315     nanosleep (& delay, nullptr);
  316     pthread_mutex_lock (& m_mutex);
  317 
  318     poll_locked ();
  319 
  320     pthread_mutex_unlock (& m_mutex);
  321 }
  322 
  323 int SndioPlugin::get_delay ()
  324 {
  325     auto timediff = [] (const timeval & a, const timeval & b) -> int64_t
  326         { return 1000 * (int64_t) (b.tv_sec - a.tv_sec) + (b.tv_usec - a.tv_usec) / 1000; };
  327 
  328     pthread_mutex_lock (& m_mutex);
  329 
  330     int delay = aud::rescale (m_frames_buffered, m_rate, 1000);
  331 
  332     if (m_last_write_time.tv_sec)
  333     {
  334         timeval now;
  335         gettimeofday (& now, nullptr);
  336         delay = aud::max (delay - timediff (m_last_write_time, now), (int64_t) 0);
  337     }
  338 
  339     pthread_mutex_unlock (& m_mutex);
  340     return delay;
  341 }
  342 
  343 void SndioPlugin::flush ()
  344 {
  345     pthread_mutex_lock (& m_mutex);
  346 
  347     sio_stop (m_handle);
  348 
  349     m_frames_buffered = 0;
  350     m_last_write_time = timeval ();
  351     m_flush_count ++;
  352 
  353     if (! sio_start (m_handle))
  354         AUDERR ("sio_start() failed\n");
  355 
  356     pthread_cond_broadcast (& m_cond);
  357     pthread_mutex_unlock (& m_mutex);
  358 }