Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
output.c
Go to the documentation of this file.
00001 /*
00002  * output.c
00003  * Copyright 2009-2010 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <math.h>
00023 
00024 #include <libaudcore/audio.h>
00025 
00026 #include "audconfig.h"
00027 #include "debug.h"
00028 #include "effect.h"
00029 #include "equalizer.h"
00030 #include "output.h"
00031 #include "playback.h"
00032 #include "plugins.h"
00033 #include "vis_runner.h"
00034 
00035 #define SW_VOLUME_RANGE 40 /* decibels */
00036 
00037 OutputPlugin * current_output_plugin = NULL;
00038 #define COP current_output_plugin
00039 
00040 static gboolean plugin_list_func (PluginHandle * plugin, GList * * list)
00041 {
00042     OutputPlugin * op = plugin_get_header (plugin);
00043     g_return_val_if_fail (op != NULL, TRUE);
00044     * list = g_list_prepend (* list, op);
00045     return TRUE;
00046 }
00047 
00048 GList * get_output_list (void)
00049 {
00050     static GList * list = NULL;
00051 
00052     if (list == NULL)
00053     {
00054         plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc)
00055          plugin_list_func, & list);
00056         list = g_list_reverse (list);
00057     }
00058 
00059     return list;
00060 }
00061 
00062 void output_get_volume (gint * l, gint * r)
00063 {
00064     if (cfg.software_volume_control)
00065     {
00066         * l = cfg.sw_volume_left;
00067         * r = cfg.sw_volume_right;
00068     }
00069     else if (COP != NULL && COP->get_volume != NULL)
00070         COP->get_volume (l, r);
00071     else
00072     {
00073         * l = 0;
00074         * r = 0;
00075     }
00076 }
00077 
00078 void output_set_volume (gint l, gint r)
00079 {
00080     if (cfg.software_volume_control)
00081     {
00082         cfg.sw_volume_left = l;
00083         cfg.sw_volume_right = r;
00084     }
00085     else if (COP != NULL && COP->set_volume != NULL)
00086         COP->set_volume (l, r);
00087 }
00088 
00089 static GMutex * output_mutex;
00090 static gboolean output_opened, output_aborted, output_leave_open, output_paused;
00091 
00092 static gint decoder_format, output_format;
00093 static gint decoder_channels, decoder_rate, effect_channels, effect_rate,
00094  output_channels, output_rate;
00095 static gint64 frames_written;
00096 static gboolean have_replay_gain;
00097 static ReplayGainInfo replay_gain_info;
00098 
00099 #define REMOVE_SOURCE(s) \
00100 do { \
00101     if (s != 0) { \
00102         g_source_remove (s); \
00103         s = 0; \
00104     } \
00105 } while (0)
00106 
00107 #define LOCK g_mutex_lock (output_mutex)
00108 #define UNLOCK g_mutex_unlock (output_mutex)
00109 
00110 static void write_buffers (void);
00111 static void drain (void);
00112 
00113 /* output_mutex must be locked */
00114 static void real_close (void)
00115 {
00116     vis_runner_start_stop (FALSE, FALSE);
00117     COP->close_audio ();
00118     output_opened = FALSE;
00119     output_leave_open = FALSE;
00120 }
00121 
00122 void output_init (void)
00123 {
00124     output_mutex = g_mutex_new ();
00125     output_opened = FALSE;
00126     output_leave_open = FALSE;
00127 }
00128 
00129 void output_cleanup (void)
00130 {
00131     LOCK;
00132 
00133     if (output_leave_open)
00134         real_close ();
00135 
00136     UNLOCK;
00137 
00138     g_mutex_free (output_mutex);
00139 }
00140 
00141 static gboolean output_open_audio (gint format, gint rate, gint channels)
00142 {
00143     if (COP == NULL)
00144     {
00145         fprintf (stderr, "No output plugin selected.\n");
00146         return FALSE;
00147     }
00148 
00149     LOCK;
00150 
00151     if (output_leave_open && COP->set_written_time != NULL)
00152     {
00153         vis_runner_time_offset (- COP->written_time ());
00154         COP->set_written_time (0);
00155     }
00156 
00157     decoder_format = format;
00158     decoder_channels = channels;
00159     decoder_rate = rate;
00160     frames_written = 0;
00161 
00162     effect_channels = channels;
00163     effect_rate = rate;
00164     effect_start (& effect_channels, & effect_rate);
00165     eq_set_format (effect_channels, effect_rate);
00166 
00167     if (output_leave_open && COP->set_written_time != NULL && effect_channels ==
00168      output_channels && effect_rate == output_rate)
00169         output_opened = TRUE;
00170     else
00171     {
00172         if (output_leave_open)
00173         {
00174             UNLOCK;
00175             drain ();
00176             LOCK;
00177             real_close ();
00178         }
00179 
00180         output_format = cfg.output_bit_depth == 32 ? FMT_S32_NE :
00181          cfg.output_bit_depth == 24 ? FMT_S24_NE : cfg.output_bit_depth == 16 ?
00182          FMT_S16_NE : FMT_FLOAT;
00183         output_channels = effect_channels;
00184         output_rate = effect_rate;
00185 
00186         if (COP->open_audio (output_format, output_rate, output_channels) > 0)
00187         {
00188             vis_runner_start_stop (TRUE, FALSE);
00189             output_opened = TRUE;
00190         }
00191     }
00192 
00193     output_aborted = FALSE;
00194     output_leave_open = FALSE;
00195     output_paused = FALSE;
00196 
00197     UNLOCK;
00198     return output_opened;
00199 }
00200 
00201 static void output_close_audio (void)
00202 {
00203     LOCK;
00204 
00205     output_opened = FALSE;
00206 
00207     if (! output_leave_open)
00208     {
00209         effect_flush ();
00210         real_close ();
00211     }
00212 
00213     UNLOCK;
00214 }
00215 
00216 static void output_flush (gint time)
00217 {
00218     LOCK;
00219 
00220     frames_written = time * (gint64) decoder_rate / 1000;
00221     output_aborted = FALSE;
00222 
00223     vis_runner_flush ();
00224     effect_flush ();
00225     COP->flush (effect_decoder_to_output_time (time));
00226 
00227     UNLOCK;
00228 }
00229 
00230 static void output_pause (gboolean pause)
00231 {
00232     LOCK;
00233     COP->pause (pause);
00234     vis_runner_start_stop (TRUE, pause);
00235     output_paused = pause;
00236     UNLOCK;
00237 }
00238 
00239 static gint get_written_time (void)
00240 {
00241     gint time = 0;
00242 
00243     LOCK;
00244 
00245     if (output_opened)
00246         time = frames_written * (gint64) 1000 / decoder_rate;
00247 
00248     UNLOCK;
00249     return time;
00250 }
00251 
00252 static gboolean output_buffer_playing (void)
00253 {
00254     LOCK;
00255 
00256     if (! output_paused)
00257     {
00258         UNLOCK;
00259         write_buffers ();
00260         LOCK;
00261         output_leave_open = TRUE;
00262     }
00263 
00264     UNLOCK;
00265     return FALSE;
00266 }
00267 
00268 static void output_set_replaygain_info (ReplayGainInfo * info)
00269 {
00270     AUDDBG ("Replay Gain info:\n");
00271     AUDDBG (" album gain: %f dB\n", info->album_gain);
00272     AUDDBG (" album peak: %f\n", info->album_peak);
00273     AUDDBG (" track gain: %f dB\n", info->track_gain);
00274     AUDDBG (" track peak: %f\n", info->track_peak);
00275 
00276     have_replay_gain = TRUE;
00277     memcpy (& replay_gain_info, info, sizeof (ReplayGainInfo));
00278 }
00279 
00280 static void apply_replay_gain (gfloat * data, gint samples)
00281 {
00282     gfloat factor = powf (10, (gfloat) cfg.replay_gain_preamp / 20);
00283 
00284     if (! cfg.enable_replay_gain)
00285         return;
00286 
00287     if (have_replay_gain)
00288     {
00289         if (cfg.replay_gain_album)
00290         {
00291             factor *= powf (10, replay_gain_info.album_gain / 20);
00292 
00293             if (cfg.enable_clipping_prevention &&
00294              replay_gain_info.album_peak * factor > 1)
00295                 factor = 1 / replay_gain_info.album_peak;
00296         }
00297         else
00298         {
00299             factor *= powf (10, replay_gain_info.track_gain / 20);
00300 
00301             if (cfg.enable_clipping_prevention &&
00302              replay_gain_info.track_peak * factor > 1)
00303                 factor = 1 / replay_gain_info.track_peak;
00304         }
00305     }
00306     else
00307         factor *= powf (10, (gfloat) cfg.default_gain / 20);
00308 
00309     if (factor < 0.99 || factor > 1.01)
00310         audio_amplify (data, 1, samples, & factor);
00311 }
00312 
00313 static void apply_software_volume (gfloat * data, gint channels, gint frames)
00314 {
00315     gfloat left_factor, right_factor;
00316     gfloat factors[channels];
00317     gint channel;
00318 
00319     if (! cfg.software_volume_control || (cfg.sw_volume_left == 100 &&
00320      cfg.sw_volume_right == 100))
00321         return;
00322 
00323     left_factor = (cfg.sw_volume_left == 0) ? 0 : powf (10, (gfloat)
00324      SW_VOLUME_RANGE * (cfg.sw_volume_left - 100) / 100 / 20);
00325     right_factor = (cfg.sw_volume_right == 0) ? 0 : powf (10, (gfloat)
00326      SW_VOLUME_RANGE * (cfg.sw_volume_right - 100) / 100 / 20);
00327 
00328     if (channels == 2)
00329     {
00330         factors[0] = left_factor;
00331         factors[1] = right_factor;
00332     }
00333     else
00334     {
00335         for (channel = 0; channel < channels; channel ++)
00336             factors[channel] = MAX (left_factor, right_factor);
00337     }
00338 
00339     audio_amplify (data, channels, frames, factors);
00340 }
00341 
00342 static void do_write (void * data, gint samples)
00343 {
00344     if (! samples)
00345         return;
00346 
00347     void * allocated = NULL;
00348 
00349     vis_runner_pass_audio (COP->written_time (), data, samples, output_channels,
00350      output_rate);
00351     eq_filter (data, samples);
00352     apply_software_volume (data, output_channels, samples / output_channels);
00353 
00354     if (output_format != FMT_FLOAT)
00355     {
00356         void * new = g_malloc (FMT_SIZEOF (output_format) * samples);
00357 
00358         audio_to_int (data, new, output_format, samples);
00359 
00360         data = new;
00361         g_free (allocated);
00362         allocated = new;
00363     }
00364 
00365     while (1)
00366     {
00367         gint ready;
00368 
00369         if (COP->buffer_free)
00370             ready = COP->buffer_free () / FMT_SIZEOF (output_format);
00371         else
00372             ready = output_channels * (output_rate / 50);
00373 
00374         LOCK;
00375 
00376         if (output_aborted)
00377         {
00378             UNLOCK;
00379             break;
00380         }
00381 
00382         UNLOCK;
00383 
00384         ready = MIN (ready, samples);
00385         COP->write_audio (data, FMT_SIZEOF (output_format) * ready);
00386         data = (char *) data + FMT_SIZEOF (output_format) * ready;
00387         samples -= ready;
00388 
00389         if (! samples)
00390             break;
00391 
00392         if (COP->period_wait)
00393             COP->period_wait ();
00394         else if (COP->buffer_free)
00395             g_usleep (20000);
00396     }
00397 
00398     g_free (allocated);
00399 }
00400 
00401 static void output_write_audio (void * data, gint size)
00402 {
00403     gint samples = size / FMT_SIZEOF (decoder_format);
00404     void * allocated = NULL;
00405 
00406     LOCK;
00407     frames_written += samples / decoder_channels;
00408     UNLOCK;
00409 
00410     if (decoder_format != FMT_FLOAT)
00411     {
00412         gfloat * new = g_malloc (sizeof (gfloat) * samples);
00413 
00414         audio_from_int (data, decoder_format, new, samples);
00415 
00416         data = new;
00417         g_free (allocated);
00418         allocated = new;
00419     }
00420 
00421     apply_replay_gain (data, samples);
00422     gfloat * fdata = data;
00423     effect_process (& fdata, & samples);
00424     data = fdata;
00425 
00426     if (data != allocated)
00427     {
00428         g_free (allocated);
00429         allocated = NULL;
00430     }
00431 
00432     do_write (data, samples);
00433     g_free (allocated);
00434 }
00435 
00436 static void write_buffers (void)
00437 {
00438     gfloat * data = NULL;
00439     gint samples = 0;
00440 
00441     effect_finish (& data, & samples);
00442     do_write (data, samples);
00443 }
00444 
00445 static void abort_write (void)
00446 {
00447     LOCK;
00448     output_aborted = TRUE;
00449     COP->flush (COP->output_time ()); /* signal wait to return immediately */
00450     UNLOCK;
00451 }
00452 
00453 static void drain (void)
00454 {
00455     if (COP->buffer_playing != NULL)
00456     {
00457         while (COP->buffer_playing ())
00458             g_usleep (30000);
00459     }
00460     else
00461         COP->drain ();
00462 }
00463 
00464 struct OutputAPI output_api =
00465 {
00466     .open_audio = output_open_audio,
00467     .set_replaygain_info = output_set_replaygain_info,
00468     .write_audio = output_write_audio,
00469     .close_audio = output_close_audio,
00470 
00471     .pause = output_pause,
00472     .flush = output_flush,
00473     .written_time = get_written_time,
00474     .buffer_playing = output_buffer_playing,
00475     .abort_write = abort_write,
00476 };
00477 
00478 gint get_output_time (void)
00479 {
00480     gint time = 0;
00481 
00482     LOCK;
00483 
00484     if (output_opened)
00485     {
00486         time = effect_output_to_decoder_time (COP->output_time ());
00487         time = MAX (0, time);
00488     }
00489 
00490     UNLOCK;
00491     return time;
00492 }
00493 
00494 void output_drain (void)
00495 {
00496     LOCK;
00497 
00498     if (output_leave_open)
00499     {
00500         UNLOCK;
00501         write_buffers (); /* tell effect plugins this is the last song */
00502         drain ();
00503         LOCK;
00504         real_close ();
00505     }
00506 
00507     UNLOCK;
00508 }
00509 
00510 void set_current_output_plugin (OutputPlugin * plugin)
00511 {
00512     OutputPlugin * old = COP;
00513     gboolean playing = playback_get_playing ();
00514     gboolean paused = FALSE;
00515     gint time = 0;
00516 
00517     if (playing)
00518     {
00519         paused = playback_get_paused ();
00520         time = playback_get_time ();
00521         playback_stop ();
00522     }
00523 
00524     /* This function is also used to restart playback (for example, when
00525      resampling is switched on or off), in which case we don't need to do an
00526      init cycle. -jlindgren */
00527     if (plugin != COP)
00528     {
00529         COP = NULL;
00530 
00531         if (old != NULL && old->cleanup != NULL)
00532             old->cleanup ();
00533 
00534         if (plugin->init () == OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00535             COP = plugin;
00536         else
00537         {
00538             fprintf (stderr, "Output plugin failed to load: %s\n",
00539              plugin->description);
00540 
00541             if (old == NULL || old->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00542                 return;
00543 
00544             fprintf (stderr, "Falling back to: %s\n", old->description);
00545             COP = old;
00546         }
00547     }
00548 
00549     if (playing)
00550         playback_play (time, paused);
00551 }