| File: | build-analysis/../src/plugins/jack/jack.c |
| Warning: | line 421, column 26 Assigned value is garbage or undefined |
| 1 | /* XMMS2 - X Music Multiplexer System | |||
| 2 | * Copyright (C) 2003-2017 XMMS2 Team | |||
| 3 | * | |||
| 4 | * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! | |||
| 5 | * | |||
| 6 | * This library is free software; you can redistribute it and/or | |||
| 7 | * modify it under the terms of the GNU Lesser General Public | |||
| 8 | * License as published by the Free Software Foundation; either | |||
| 9 | * version 2.1 of the License, or (at your option) any later version. | |||
| 10 | * | |||
| 11 | * This library is distributed in the hope that it will be useful, | |||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 14 | * Lesser General Public License for more details. | |||
| 15 | */ | |||
| 16 | ||||
| 17 | #include <xmms/xmms_outputplugin.h> | |||
| 18 | #include <xmms/xmms_log.h> | |||
| 19 | ||||
| 20 | #include <stdio.h> | |||
| 21 | ||||
| 22 | #include <glib.h> | |||
| 23 | #include <jack/jack.h> | |||
| 24 | ||||
| 25 | ||||
| 26 | /* | |||
| 27 | * Defines | |||
| 28 | */ | |||
| 29 | ||||
| 30 | /* this isn't really what we want... */ | |||
| 31 | #define CHANNELS2 2 | |||
| 32 | ||||
| 33 | ||||
| 34 | /* | |||
| 35 | * Type definitions | |||
| 36 | */ | |||
| 37 | ||||
| 38 | typedef struct xmms_jack_data_St { | |||
| 39 | jack_client_t *jack; | |||
| 40 | jack_port_t *ports[CHANNELS2]; | |||
| 41 | /* ports */ | |||
| 42 | gint chunksiz; | |||
| 43 | gboolean error; | |||
| 44 | gboolean running; | |||
| 45 | guint underruns; | |||
| 46 | guint volume[CHANNELS2]; | |||
| 47 | gfloat volume_actual[CHANNELS2]; | |||
| 48 | gfloat new_volume_actual[CHANNELS2]; | |||
| 49 | gint last_sign[CHANNELS2]; | |||
| 50 | GMutex volume_change; /* This should not be needed once the server doesn't allow multiple clients to set the volume at the same time */ | |||
| 51 | } xmms_jack_data_t; | |||
| 52 | ||||
| 53 | ||||
| 54 | /* | |||
| 55 | * Function prototypes | |||
| 56 | */ | |||
| 57 | ||||
| 58 | static gboolean xmms_jack_plugin_setup (xmms_output_plugin_t *plugin); | |||
| 59 | static gboolean xmms_jack_new (xmms_output_t *output); | |||
| 60 | static void xmms_jack_destroy (xmms_output_t *output); | |||
| 61 | static gboolean xmms_jack_status (xmms_output_t *output, xmms_playback_status_t status); | |||
| 62 | static void xmms_jack_flush (xmms_output_t *output); | |||
| 63 | static gboolean xmms_jack_volume_set (xmms_output_t *output, const gchar *channel, guint volume); | |||
| 64 | static gboolean xmms_jack_volume_get (xmms_output_t *output, const gchar **names, guint *values, guint *num_channels); | |||
| 65 | static int xmms_jack_process (jack_nframes_t frames, void *arg); | |||
| 66 | static void xmms_jack_shutdown (void *arg); | |||
| 67 | static void xmms_jack_error (const gchar *desc); | |||
| 68 | static gboolean xmms_jack_ports_connected (xmms_output_t *output); | |||
| 69 | static gboolean xmms_jack_connect_ports (xmms_output_t *output); | |||
| 70 | static gboolean xmms_jack_connect (xmms_output_t *output); | |||
| 71 | ||||
| 72 | /* | |||
| 73 | * Plugin header | |||
| 74 | */ | |||
| 75 | ||||
| 76 | XMMS_OUTPUT_PLUGIN_DEFINE ("jack", "Jack Output", XMMS_VERSION,xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_OUTPUT, 8, "jack", "Jack Output", "clang-analysis" , "Jack audio server output plugin", (gboolean (*)(gpointer)) xmms_jack_plugin_setup }; | |||
| 77 | "Jack audio server output plugin",xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_OUTPUT, 8, "jack", "Jack Output", "clang-analysis" , "Jack audio server output plugin", (gboolean (*)(gpointer)) xmms_jack_plugin_setup }; | |||
| 78 | xmms_jack_plugin_setup)xmms_plugin_desc_t __attribute__((visibility ("default"))) XMMS_PLUGIN_DESC = { XMMS_PLUGIN_TYPE_OUTPUT, 8, "jack", "Jack Output", "clang-analysis" , "Jack audio server output plugin", (gboolean (*)(gpointer)) xmms_jack_plugin_setup };; | |||
| 79 | ||||
| 80 | static gboolean | |||
| 81 | xmms_jack_plugin_setup (xmms_output_plugin_t *plugin) | |||
| 82 | { | |||
| 83 | xmms_output_methods_t methods; | |||
| 84 | ||||
| 85 | XMMS_OUTPUT_METHODS_INIT (methods)memset (&methods, 0, sizeof (xmms_output_methods_t)); | |||
| 86 | ||||
| 87 | methods.new = xmms_jack_new; | |||
| 88 | methods.destroy = xmms_jack_destroy; | |||
| 89 | methods.status = xmms_jack_status; | |||
| 90 | methods.flush = xmms_jack_flush; | |||
| 91 | methods.volume_get = xmms_jack_volume_get; | |||
| 92 | methods.volume_set = xmms_jack_volume_set; | |||
| 93 | ||||
| 94 | xmms_output_plugin_methods_set (plugin, &methods); | |||
| 95 | ||||
| 96 | xmms_output_plugin_config_property_register (plugin, "clientname", "XMMS2", | |||
| 97 | NULL((void*)0), NULL((void*)0)); | |||
| 98 | ||||
| 99 | xmms_output_plugin_config_property_register (plugin, "connect_ports", "1", | |||
| 100 | NULL((void*)0), NULL((void*)0)); | |||
| 101 | ||||
| 102 | xmms_output_plugin_config_property_register (plugin, "connect_to_ports", "physical", | |||
| 103 | NULL((void*)0), NULL((void*)0)); | |||
| 104 | ||||
| 105 | xmms_output_plugin_config_property_register (plugin, "volume.left", "100", | |||
| 106 | NULL((void*)0), NULL((void*)0)); | |||
| 107 | ||||
| 108 | xmms_output_plugin_config_property_register (plugin, "volume.right", "100", | |||
| 109 | NULL((void*)0), NULL((void*)0)); | |||
| 110 | ||||
| 111 | jack_set_error_function (xmms_jack_error); | |||
| 112 | ||||
| 113 | return TRUE(!(0)); | |||
| 114 | } | |||
| 115 | ||||
| 116 | ||||
| 117 | /* | |||
| 118 | * Member functions | |||
| 119 | */ | |||
| 120 | ||||
| 121 | ||||
| 122 | static gboolean | |||
| 123 | xmms_jack_connect (xmms_output_t *output) | |||
| 124 | { | |||
| 125 | int i; | |||
| 126 | const xmms_config_property_t *cv; | |||
| 127 | const gchar *clientname; | |||
| 128 | xmms_jack_data_t *data; | |||
| 129 | ||||
| 130 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 131 | data = xmms_output_private_data_get (output); | |||
| 132 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 133 | ||||
| 134 | cv = xmms_output_config_lookup (output, "clientname"); | |||
| 135 | clientname = xmms_config_property_get_string (cv); | |||
| 136 | ||||
| 137 | data->jack = jack_client_open (clientname, JackNullOption, NULL((void*)0)); | |||
| 138 | if (!data->jack) { | |||
| 139 | return FALSE(0); | |||
| 140 | } | |||
| 141 | ||||
| 142 | jack_set_process_callback (data->jack, xmms_jack_process, output); | |||
| 143 | jack_on_shutdown (data->jack, xmms_jack_shutdown, output); | |||
| 144 | ||||
| 145 | ||||
| 146 | for (i = 0; i < CHANNELS2; i++) { | |||
| 147 | gchar name[16]; | |||
| 148 | g_snprintf (name, sizeof (name), "out_%d", i + 1); | |||
| 149 | data->ports[i] = jack_port_register (data->jack, name, | |||
| 150 | JACK_DEFAULT_AUDIO_TYPE"32 bit float mono audio", | |||
| 151 | (JackPortIsOutput | | |||
| 152 | JackPortIsTerminal), 0); | |||
| 153 | } | |||
| 154 | ||||
| 155 | data->chunksiz = jack_get_buffer_size (data->jack); | |||
| 156 | ||||
| 157 | if (jack_activate (data->jack)) { | |||
| 158 | /* jadda jadda */ | |||
| 159 | jack_client_close (data->jack); | |||
| 160 | return FALSE(0); | |||
| 161 | } | |||
| 162 | ||||
| 163 | data->error = FALSE(0); | |||
| 164 | ||||
| 165 | return TRUE(!(0)); | |||
| 166 | } | |||
| 167 | ||||
| 168 | ||||
| 169 | static gboolean | |||
| 170 | xmms_jack_new (xmms_output_t *output) | |||
| 171 | { | |||
| 172 | xmms_jack_data_t *data; | |||
| 173 | xmms_config_property_t *cv; | |||
| 174 | int connect; | |||
| 175 | ||||
| 176 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 177 | ||||
| 178 | data = g_new0 (xmms_jack_data_t, 1)((xmms_jack_data_t *) g_malloc0_n ((1), sizeof (xmms_jack_data_t ))); | |||
| 179 | ||||
| 180 | data->underruns = 0; | |||
| 181 | ||||
| 182 | cv = xmms_output_config_lookup (output, "volume.left"); | |||
| 183 | data->volume[0] = xmms_config_property_get_int (cv); | |||
| 184 | ||||
| 185 | cv = xmms_output_config_lookup (output, "volume.right"); | |||
| 186 | data->volume[1] = xmms_config_property_get_int (cv); | |||
| 187 | ||||
| 188 | data->volume_actual[0] = (gfloat)(data->volume[0] / 100.0); | |||
| 189 | data->volume_actual[0] *= data->volume_actual[0]; | |||
| 190 | data->new_volume_actual[0] = data->volume_actual[0]; | |||
| 191 | data->volume_actual[1] = (gfloat)(data->volume[1] / 100.0); | |||
| 192 | data->volume_actual[1] *= data->volume_actual[1]; | |||
| 193 | data->new_volume_actual[1] = data->volume_actual[1]; | |||
| 194 | ||||
| 195 | g_mutex_init (&data->volume_change); | |||
| 196 | ||||
| 197 | ||||
| 198 | xmms_output_private_data_set (output, data); | |||
| 199 | ||||
| 200 | if (!xmms_jack_connect (output)) { | |||
| 201 | g_mutex_clear (&data->volume_change); | |||
| 202 | g_free (data); | |||
| 203 | return FALSE(0); | |||
| 204 | } | |||
| 205 | ||||
| 206 | xmms_output_format_add (output, XMMS_SAMPLE_FORMAT_FLOAT, CHANNELS,xmms_output_stream_type_add (output, XMMS_STREAM_TYPE_MIMETYPE , "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT , XMMS_STREAM_TYPE_FMT_CHANNELS, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE , jack_get_sample_rate (data->jack), XMMS_STREAM_TYPE_END) | |||
| 207 | jack_get_sample_rate (data->jack))xmms_output_stream_type_add (output, XMMS_STREAM_TYPE_MIMETYPE , "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT , XMMS_STREAM_TYPE_FMT_CHANNELS, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE , jack_get_sample_rate (data->jack), XMMS_STREAM_TYPE_END); | |||
| 208 | ||||
| 209 | cv = xmms_output_config_lookup (output, "connect_ports"); | |||
| 210 | connect = xmms_config_property_get_int (cv); | |||
| 211 | ||||
| 212 | if (connect == 1) { | |||
| 213 | ||||
| 214 | if (!xmms_jack_ports_connected (output) && !xmms_jack_connect_ports (output)) { | |||
| 215 | g_mutex_clear (&data->volume_change); | |||
| 216 | g_free (data); | |||
| 217 | return FALSE(0); | |||
| 218 | } | |||
| 219 | ||||
| 220 | } | |||
| 221 | ||||
| 222 | return TRUE(!(0)); | |||
| 223 | } | |||
| 224 | ||||
| 225 | ||||
| 226 | static void | |||
| 227 | xmms_jack_destroy (xmms_output_t *output) | |||
| 228 | { | |||
| 229 | xmms_jack_data_t *data; | |||
| 230 | ||||
| 231 | g_return_if_fail (output)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return; }; }while (0); | |||
| 232 | data = xmms_output_private_data_get (output); | |||
| 233 | g_return_if_fail (data)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return; }; }while (0); | |||
| 234 | ||||
| 235 | g_mutex_clear (&data->volume_change); | |||
| 236 | ||||
| 237 | if (data->jack) { | |||
| 238 | jack_deactivate (data->jack); | |||
| 239 | jack_client_close (data->jack); | |||
| 240 | } | |||
| 241 | ||||
| 242 | g_free (data); | |||
| 243 | } | |||
| 244 | ||||
| 245 | ||||
| 246 | static gboolean | |||
| 247 | xmms_jack_ports_connected (xmms_output_t *output) | |||
| 248 | { | |||
| 249 | xmms_jack_data_t *data; | |||
| 250 | ||||
| 251 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 252 | data = xmms_output_private_data_get (output); | |||
| 253 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 254 | ||||
| 255 | gint is_connected = 0; | |||
| 256 | gint i; | |||
| 257 | ||||
| 258 | for (i = 0; i < CHANNELS2; i++) { | |||
| 259 | is_connected += jack_port_connected (data->ports[i]); | |||
| 260 | } | |||
| 261 | ||||
| 262 | return (is_connected > 0); | |||
| 263 | } | |||
| 264 | ||||
| 265 | static gboolean | |||
| 266 | xmms_jack_connect_ports (xmms_output_t *output) | |||
| 267 | { | |||
| 268 | const gchar *ports; | |||
| 269 | const gchar **remote_ports; | |||
| 270 | gboolean ret = TRUE(!(0)); | |||
| 271 | gint i, err; | |||
| 272 | xmms_config_property_t *cv; | |||
| 273 | xmms_jack_data_t *data; | |||
| 274 | ||||
| 275 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 276 | data = xmms_output_private_data_get (output); | |||
| 277 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 278 | ||||
| 279 | cv = xmms_output_config_lookup (output, "connect_to_ports"); | |||
| 280 | ports = xmms_config_property_get_string (cv); | |||
| 281 | ||||
| 282 | if ((strlen(ports) == 0) || ((strncmp(ports, "physical", 8) == 0))) { | |||
| 283 | ||||
| 284 | remote_ports = jack_get_ports (data->jack, NULL((void*)0), NULL((void*)0), | |||
| 285 | JackPortIsInput | JackPortIsPhysical); | |||
| 286 | ||||
| 287 | } else { | |||
| 288 | ||||
| 289 | remote_ports = jack_get_ports (data->jack, ports, NULL((void*)0), JackPortIsInput); | |||
| 290 | ||||
| 291 | } | |||
| 292 | ||||
| 293 | for (i = 0; i < CHANNELS2 && remote_ports && remote_ports[i]; i++) { | |||
| 294 | const gchar *src_port = jack_port_name (data->ports[i]); | |||
| 295 | ||||
| 296 | err = jack_connect (data->jack, src_port, remote_ports[i]); | |||
| 297 | if (err < 0) { | |||
| 298 | ret = FALSE(0); | |||
| 299 | break; | |||
| 300 | } | |||
| 301 | } | |||
| 302 | ||||
| 303 | return ret; | |||
| 304 | } | |||
| 305 | ||||
| 306 | static gboolean | |||
| 307 | xmms_jack_status (xmms_output_t *output, xmms_playback_status_t status) | |||
| 308 | { | |||
| 309 | xmms_jack_data_t *data; | |||
| 310 | ||||
| 311 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 312 | data = xmms_output_private_data_get (output); | |||
| 313 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 314 | ||||
| 315 | if (status == XMMS_PLAYBACK_STATUS_PLAY) { | |||
| 316 | data->running = TRUE(!(0)); | |||
| 317 | } else { | |||
| 318 | data->running = FALSE(0); | |||
| 319 | } | |||
| 320 | ||||
| 321 | return TRUE(!(0)); | |||
| 322 | } | |||
| 323 | ||||
| 324 | ||||
| 325 | static void | |||
| 326 | xmms_jack_flush (xmms_output_t *output) | |||
| 327 | { | |||
| 328 | /* do nothing... */ | |||
| 329 | } | |||
| 330 | ||||
| 331 | ||||
| 332 | static int | |||
| 333 | xmms_jack_process (jack_nframes_t frames, void *arg) | |||
| 334 | { | |||
| 335 | xmms_output_t *output = (xmms_output_t*) arg; | |||
| 336 | xmms_jack_data_t *data; | |||
| 337 | xmms_samplefloat_t *buf[CHANNELS2]; | |||
| 338 | xmms_samplefloat_t tbuf[CHANNELS2*4096]; | |||
| 339 | gint i, j, res, toread, sign; | |||
| ||||
| 340 | ||||
| 341 | g_return_val_if_fail (output, -1)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return (-1); }; } while (0); | |||
| 342 | data = xmms_output_private_data_get (output); | |||
| 343 | g_return_val_if_fail (data, -1)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return (-1); }; }while (0); | |||
| 344 | ||||
| 345 | for (i = 0; i < CHANNELS2; i++) { | |||
| 346 | buf[i] = jack_port_get_buffer (data->ports[i], frames); | |||
| 347 | } | |||
| 348 | ||||
| 349 | toread = frames; | |||
| 350 | ||||
| 351 | if (data->running) { | |||
| 352 | while (toread) { | |||
| 353 | gint t, avail; | |||
| 354 | ||||
| 355 | t = MIN (toread * CHANNELS * sizeof (xmms_samplefloat_t),(((toread * 2 * sizeof (xmms_samplefloat_t)) < (sizeof (tbuf ))) ? (toread * 2 * sizeof (xmms_samplefloat_t)) : (sizeof (tbuf ))) | |||
| 356 | sizeof (tbuf))(((toread * 2 * sizeof (xmms_samplefloat_t)) < (sizeof (tbuf ))) ? (toread * 2 * sizeof (xmms_samplefloat_t)) : (sizeof (tbuf ))); | |||
| 357 | ||||
| 358 | avail = xmms_output_bytes_available (output); | |||
| 359 | ||||
| 360 | if (avail < t) { | |||
| 361 | data->underruns++; | |||
| 362 | XMMS_DBG ("jack output underun number %d! Not enough bytes available. Wanted: %d Available: %d", data->underruns, t, avail)g_debug ("../src/plugins/jack/jack.c" ":" "362" ": " "jack output underun number %d! Not enough bytes available. Wanted: %d Available: %d" , data->underruns, t, avail); | |||
| 363 | break; | |||
| 364 | } | |||
| 365 | ||||
| 366 | res = xmms_output_read (output, (gchar *)tbuf, t); | |||
| 367 | ||||
| 368 | if (res <= 0) { | |||
| 369 | XMMS_DBG ("Output read returned %d unexpectedly", res)g_debug ("../src/plugins/jack/jack.c" ":" "369" ": " "Output read returned %d unexpectedly" , res); | |||
| 370 | break; | |||
| 371 | } | |||
| 372 | ||||
| 373 | if (res < t) { | |||
| 374 | XMMS_DBG ("Less bytes read than expected. (Probably a ringbuffer hotspot)")g_debug ("../src/plugins/jack/jack.c" ":" "374" ": " "Less bytes read than expected. (Probably a ringbuffer hotspot)" ); | |||
| 375 | } | |||
| 376 | ||||
| 377 | res /= CHANNELS2 * sizeof (xmms_samplefloat_t); | |||
| 378 | ||||
| 379 | for (j = 0; j < CHANNELS2; j++) { | |||
| 380 | if (data->new_volume_actual[j] == data->volume_actual[j]) { | |||
| 381 | for (i = 0; i < res; i++) { | |||
| 382 | buf[j][i] = (tbuf[i * CHANNELS2 + j] * data->volume_actual[j]); | |||
| 383 | } | |||
| 384 | } else { | |||
| 385 | ||||
| 386 | /* The way the volume change is set up here, the volume can only change once per callback, but thats | |||
| 387 | allways plenty of times per second */ | |||
| 388 | ||||
| 389 | /* last_sign: 0 = unset, -1 neg, +1 pos */ | |||
| 390 | ||||
| 391 | if (data->last_sign[j] == 0) { | |||
| 392 | if (tbuf[j] > 0.0f) { | |||
| 393 | data->last_sign[j] = 1; | |||
| 394 | } else { | |||
| 395 | /* Zero counts as negative here, but its moot */ | |||
| 396 | data->last_sign[j] = -1; | |||
| 397 | } | |||
| 398 | } | |||
| 399 | ||||
| 400 | for (i = 0; i < res; i++) { | |||
| 401 | ||||
| 402 | if (data->last_sign[j] != 0) { | |||
| 403 | if (tbuf[i*CHANNELS2 + j] > 0.0f) { | |||
| 404 | sign = 1; | |||
| 405 | } else { | |||
| 406 | sign = -1; | |||
| 407 | } | |||
| 408 | ||||
| 409 | if ((sign != data->last_sign[j]) || (tbuf[i * CHANNELS2 + j] == 0.0f)) { | |||
| 410 | ||||
| 411 | data->volume_actual[j] = data->new_volume_actual[j]; | |||
| 412 | data->last_sign[j] = 0; | |||
| 413 | } | |||
| 414 | } | |||
| 415 | ||||
| 416 | buf[j][i] = (tbuf[i * CHANNELS2 + j] * data->volume_actual[j]); | |||
| 417 | ||||
| 418 | } | |||
| 419 | ||||
| 420 | if (data->last_sign[j] != 0) { | |||
| 421 | data->last_sign[j] = sign; | |||
| ||||
| 422 | } | |||
| 423 | } | |||
| 424 | } | |||
| 425 | ||||
| 426 | toread -= res; | |||
| 427 | } | |||
| 428 | } | |||
| 429 | ||||
| 430 | if ((!data->running) || ((frames - toread) != frames)) { | |||
| 431 | /* fill rest of buffer with silence */ | |||
| 432 | if (data->running) { | |||
| 433 | XMMS_DBG ("Silence for %d frames", toread)g_debug ("../src/plugins/jack/jack.c" ":" "433" ": " "Silence for %d frames" , toread); | |||
| 434 | } | |||
| 435 | for (j = 0; j < CHANNELS2; j++) { | |||
| 436 | if (data->new_volume_actual[j] != data->volume_actual[j]) { | |||
| 437 | data->volume_actual[j] = data->new_volume_actual[j]; | |||
| 438 | } | |||
| 439 | for (i = frames - toread; i < frames; i++) { | |||
| 440 | buf[j][i] = 0.0f; | |||
| 441 | } | |||
| 442 | } | |||
| 443 | } | |||
| 444 | ||||
| 445 | return 0; | |||
| 446 | } | |||
| 447 | ||||
| 448 | static gboolean | |||
| 449 | xmms_jack_volume_set (xmms_output_t *output, | |||
| 450 | const gchar *channel_name, guint volume) | |||
| 451 | { | |||
| 452 | xmms_jack_data_t *data; | |||
| 453 | xmms_config_property_t *cv; | |||
| 454 | gchar *volume_strp; | |||
| 455 | gchar volume_str[4]; | |||
| 456 | gfloat new_volume; /* For atomicness with zero crossing respect */ | |||
| 457 | ||||
| 458 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 459 | g_return_val_if_fail (channel_name, FALSE)do{ if (channel_name) { } else { g_return_if_fail_warning ((( gchar*) 0), ((const char*) (__func__)), "channel_name"); return ((0)); }; }while (0); | |||
| 460 | g_return_val_if_fail (volume <= 100, FALSE)do{ if (volume <= 100) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "volume <= 100" ); return ((0)); }; }while (0); | |||
| 461 | ||||
| 462 | volume_strp = volume_str; | |||
| 463 | ||||
| 464 | data = xmms_output_private_data_get (output); | |||
| 465 | ||||
| 466 | g_mutex_lock (&data->volume_change); | |||
| 467 | ||||
| 468 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 469 | ||||
| 470 | if (g_ascii_strcasecmp (channel_name, "Left") == 0) { | |||
| 471 | data->volume[0] = volume; | |||
| 472 | new_volume = (gfloat)(volume / 100.0); | |||
| 473 | new_volume *= new_volume; | |||
| 474 | data->new_volume_actual[0] = new_volume; | |||
| 475 | cv = xmms_output_config_lookup (output, "volume.left"); | |||
| 476 | sprintf (volume_str, "%d", data->volume[0]); | |||
| 477 | xmms_config_property_set_data (cv, volume_strp); | |||
| 478 | } else { | |||
| 479 | /* If its not left, its right */ | |||
| 480 | data->volume[1] = volume; | |||
| 481 | new_volume = (gfloat)(volume / 100.0); | |||
| 482 | new_volume *= new_volume; | |||
| 483 | data->new_volume_actual[1] = new_volume; | |||
| 484 | cv = xmms_output_config_lookup (output, "volume.right"); | |||
| 485 | sprintf (volume_str, "%d", data->volume[1]); | |||
| 486 | xmms_config_property_set_data (cv, volume_strp); | |||
| 487 | } | |||
| 488 | ||||
| 489 | g_mutex_unlock (&data->volume_change); | |||
| 490 | ||||
| 491 | return TRUE(!(0)); | |||
| 492 | } | |||
| 493 | ||||
| 494 | static gboolean | |||
| 495 | xmms_jack_volume_get (xmms_output_t *output, const gchar **names, | |||
| 496 | guint *values, guint *num_channels) | |||
| 497 | { | |||
| 498 | xmms_jack_data_t *data; | |||
| 499 | ||||
| 500 | g_return_val_if_fail (output, FALSE)do{ if (output) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "output"); return ((0)); }; }while (0); | |||
| 501 | ||||
| 502 | data = xmms_output_private_data_get (output); | |||
| 503 | ||||
| 504 | g_return_val_if_fail (data, FALSE)do{ if (data) { } else { g_return_if_fail_warning (((gchar*) 0 ), ((const char*) (__func__)), "data"); return ((0)); }; }while (0); | |||
| 505 | g_return_val_if_fail (num_channels, FALSE)do{ if (num_channels) { } else { g_return_if_fail_warning ((( gchar*) 0), ((const char*) (__func__)), "num_channels"); return ((0)); }; }while (0); | |||
| 506 | ||||
| 507 | if (!*num_channels) { | |||
| 508 | *num_channels = 2; | |||
| 509 | return TRUE(!(0)); | |||
| 510 | } | |||
| 511 | ||||
| 512 | g_return_val_if_fail (*num_channels == 2, FALSE)do{ if (*num_channels == 2) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "*num_channels == 2" ); return ((0)); }; }while (0); | |||
| 513 | g_return_val_if_fail (names, FALSE)do{ if (names) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "names"); return ((0)); }; } while (0); | |||
| 514 | g_return_val_if_fail (values, FALSE)do{ if (values) { } else { g_return_if_fail_warning (((gchar* ) 0), ((const char*) (__func__)), "values"); return ((0)); }; }while (0); | |||
| 515 | ||||
| 516 | values[0] = data->volume[0]; | |||
| 517 | names[0] = "Left"; | |||
| 518 | ||||
| 519 | values[1] = data->volume[1]; | |||
| 520 | names[1] = "Right"; | |||
| 521 | ||||
| 522 | return TRUE(!(0)); | |||
| 523 | } | |||
| 524 | ||||
| 525 | ||||
| 526 | static void | |||
| 527 | xmms_jack_shutdown (void *arg) | |||
| 528 | { | |||
| 529 | xmms_output_t *output = (xmms_output_t*) arg; | |||
| 530 | xmms_jack_data_t *data; | |||
| 531 | xmms_error_t err; | |||
| 532 | ||||
| 533 | xmms_error_reset (&err); | |||
| 534 | ||||
| 535 | data = xmms_output_private_data_get (output); | |||
| 536 | data->error = TRUE(!(0)); | |||
| 537 | ||||
| 538 | xmms_error_set (&err, XMMS_ERROR_GENERIC, "jackd has been shutdown"); | |||
| 539 | xmms_output_set_error (output, &err); | |||
| 540 | } | |||
| 541 | ||||
| 542 | ||||
| 543 | static void | |||
| 544 | xmms_jack_error (const gchar *desc) | |||
| 545 | { | |||
| 546 | xmms_log_error ("Jack reported error: %s", desc)g_warning ("../src/plugins/jack/jack.c" ":" "546" ": " "Jack reported error: %s" , desc); | |||
| 547 | } |