00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <string.h>
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020
00021 #include "xmms/xmms_object.h"
00022 #include "xmmspriv/xmms_ipc.h"
00023 #include "xmmspriv/xmms_sample.h"
00024
00025 #include "common.h"
00026
00027
00028
00029
00030
00031
00032
00033 static xmms_visualization_t *vis = NULL;
00034
00035 static int32_t xmms_visualization_client_version (xmms_visualization_t *vis, xmms_error_t *err);
00036 static int32_t xmms_visualization_client_register (xmms_visualization_t *vis, xmms_error_t *err);
00037 static int32_t xmms_visualization_client_init_shm (xmms_visualization_t *vis, int32_t id, const char *shmid, xmms_error_t *err);
00038 static int32_t xmms_visualization_client_init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err);
00039 static int32_t xmms_visualization_client_property_set (xmms_visualization_t *vis, int32_t id, const gchar *key, const gchar *value, xmms_error_t *err);
00040 static int32_t xmms_visualization_client_properties_set (xmms_visualization_t *vis, int32_t id, xmmsv_t *prop, xmms_error_t *err);
00041 static void xmms_visualization_client_shutdown (xmms_visualization_t *vis, int32_t id, xmms_error_t *err);
00042 static void xmms_visualization_destroy (xmms_object_t *object);
00043
00044
00045 XMMS_CMD_DEFINE (query_version, xmms_visualization_client_version, xmms_visualization_t *, INT32, NONE, NONE);
00046 XMMS_CMD_DEFINE (registercl, xmms_visualization_client_register, xmms_visualization_t *, INT32, NONE, NONE);
00047 XMMS_CMD_DEFINE (init_shm, xmms_visualization_client_init_shm, xmms_visualization_t *, INT32, INT32, STRING);
00048 XMMS_CMD_DEFINE (init_udp, xmms_visualization_client_init_udp, xmms_visualization_t *, INT32, INT32, NONE);
00049 XMMS_CMD_DEFINE3 (property_set, xmms_visualization_client_property_set, xmms_visualization_t *, INT32, INT32, STRING, STRING);
00050 XMMS_CMD_DEFINE (properties_set, xmms_visualization_client_properties_set, xmms_visualization_t *, INT32, INT32, DICT);
00051 XMMS_CMD_DEFINE (shutdown, xmms_visualization_client_shutdown, xmms_visualization_t *, NONE, INT32, NONE);
00052
00053
00054 static int32_t
00055 create_client (void)
00056 {
00057 int32_t id;
00058
00059 for (id = 0; id < vis->clientc; ++id) {
00060 if (!vis->clientv[id]) {
00061 break;
00062 }
00063 }
00064
00065 if (id == vis->clientc) {
00066 vis->clientc++;
00067 }
00068
00069 vis->clientv = g_renew (xmms_vis_client_t*, vis->clientv, vis->clientc);
00070 if (!vis->clientv || (!(vis->clientv[id] = g_new (xmms_vis_client_t, 1)))) {
00071 vis->clientc = 0;
00072 id = -1;
00073 }
00074
00075 xmms_log_info ("Attached visualization client %d", id);
00076 return id;
00077 }
00078
00079 xmms_vis_client_t *
00080 get_client (int32_t id)
00081 {
00082 if (id < 0 || id >= vis->clientc) {
00083 return NULL;
00084 }
00085
00086 return vis->clientv[id];
00087 }
00088
00089
00090 void
00091 delete_client (int32_t id)
00092 {
00093 xmms_vis_client_t *c;
00094
00095 if (id < 0 || id >= vis->clientc) {
00096 return;
00097 }
00098
00099 c = vis->clientv[id];
00100 if (c == NULL) {
00101 return;
00102 }
00103
00104 if (c->type == VIS_UNIXSHM) {
00105 cleanup_shm (&c->transport.shm);
00106 } else if (c->type == VIS_UDP) {
00107 cleanup_udp (&c->transport.udp, vis->socket);
00108 }
00109
00110 g_free (c);
00111 vis->clientv[id] = NULL;
00112
00113 xmms_log_info ("Removed visualization client %d", id);
00114 }
00115
00116
00117
00118
00119 xmms_visualization_t *
00120 xmms_visualization_new (xmms_output_t *output)
00121 {
00122 vis = xmms_object_new (xmms_visualization_t, xmms_visualization_destroy);
00123 vis->clientlock = g_mutex_new ();
00124 vis->clientc = 0;
00125 vis->output = output;
00126
00127 xmms_object_ref (output);
00128
00129 xmms_ipc_object_register (XMMS_IPC_OBJECT_VISUALIZATION, XMMS_OBJECT (vis));
00130 xmms_object_cmd_add (XMMS_OBJECT (vis),
00131 XMMS_IPC_CMD_VISUALIZATION_QUERY_VERSION,
00132 XMMS_CMD_FUNC (query_version));
00133 xmms_object_cmd_add (XMMS_OBJECT (vis),
00134 XMMS_IPC_CMD_VISUALIZATION_REGISTER,
00135 XMMS_CMD_FUNC (registercl));
00136 xmms_object_cmd_add (XMMS_OBJECT (vis),
00137 XMMS_IPC_CMD_VISUALIZATION_INIT_SHM,
00138 XMMS_CMD_FUNC (init_shm));
00139 xmms_object_cmd_add (XMMS_OBJECT (vis),
00140 XMMS_IPC_CMD_VISUALIZATION_INIT_UDP,
00141 XMMS_CMD_FUNC (init_udp));
00142 xmms_object_cmd_add (XMMS_OBJECT (vis),
00143 XMMS_IPC_CMD_VISUALIZATION_PROPERTY,
00144 XMMS_CMD_FUNC (property_set));
00145 xmms_object_cmd_add (XMMS_OBJECT (vis),
00146 XMMS_IPC_CMD_VISUALIZATION_PROPERTIES,
00147 XMMS_CMD_FUNC (properties_set));
00148 xmms_object_cmd_add (XMMS_OBJECT (vis),
00149 XMMS_IPC_CMD_VISUALIZATION_SHUTDOWN,
00150 XMMS_CMD_FUNC (shutdown));
00151
00152 xmms_socket_invalidate (&vis->socket);
00153
00154 return vis;
00155 }
00156
00157
00158
00159
00160
00161
00162 static void
00163 xmms_visualization_destroy (xmms_object_t *object)
00164 {
00165 xmms_object_unref (vis->output);
00166
00167
00168 g_mutex_free (vis->clientlock);
00169 xmms_log_debug ("starting cleanup of %d vis clients", vis->clientc);
00170 for (; vis->clientc > 0; --vis->clientc) {
00171 delete_client (vis->clientc - 1);
00172 }
00173
00174 if (xmms_socket_valid (vis->socket)) {
00175
00176 g_io_channel_shutdown (vis->socketio, FALSE, NULL);
00177 xmms_socket_close (vis->socket);
00178 }
00179 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_VISUALIZATION);
00180 }
00181
00182 static int32_t
00183 xmms_visualization_client_version (xmms_visualization_t *vis, xmms_error_t *err)
00184 {
00185
00186
00187
00188 return XMMS_VISPACKET_VERSION;
00189 }
00190
00191 static void
00192 properties_init (xmmsc_vis_properties_t *p)
00193 {
00194 p->type = VIS_PCM;
00195 p->stereo = 1;
00196 p->pcm_hardwire = 0;
00197 }
00198
00199 static gboolean
00200 property_set (xmmsc_vis_properties_t *p, const gchar* key, const gchar* data)
00201 {
00202
00203 if (!g_strcasecmp (key, "type")) {
00204 if (!g_strcasecmp (data, "pcm")) {
00205 p->type = VIS_PCM;
00206 } else if (!g_strcasecmp (data, "spectrum")) {
00207 p->type = VIS_SPECTRUM;
00208 } else if (!g_strcasecmp (data, "peak")) {
00209 p->type = VIS_PEAK;
00210 } else {
00211 return FALSE;
00212 }
00213 } else if (!g_strcasecmp (key, "stereo")) {
00214 p->stereo = (atoi (data) > 0);
00215 } else if (!g_strcasecmp (key, "pcm.hardwire")) {
00216 p->pcm_hardwire = (atoi (data) > 0);
00217
00218 } else if (!g_strcasecmp (key, "timeframe")) {
00219 p->timeframe = g_strtod (data, NULL);
00220 if (p->timeframe == 0.0) {
00221 return FALSE;
00222 }
00223 } else {
00224 return FALSE;
00225 }
00226 return TRUE;
00227 }
00228
00229 static int32_t
00230 xmms_visualization_client_register (xmms_visualization_t *vis, xmms_error_t *err)
00231 {
00232 int32_t id;
00233 xmms_vis_client_t *c;
00234
00235 g_mutex_lock (vis->clientlock);
00236 id = create_client ();
00237 if (id < 0) {
00238 xmms_error_set (err, XMMS_ERROR_OOM, "could not allocate dataset");
00239 } else {
00240
00241 c = get_client (id);
00242 c->type = VIS_NONE;
00243 c->format = 0;
00244 properties_init (&c->prop);
00245 }
00246 g_mutex_unlock (vis->clientlock);
00247 return id;
00248 }
00249
00250
00251 static int32_t
00252 xmms_visualization_client_property_set (xmms_visualization_t *vis, int32_t id, const gchar* key, const gchar* value, xmms_error_t *err)
00253 {
00254 xmms_vis_client_t *c;
00255
00256 x_fetch_client (id);
00257
00258 if (!property_set (&c->prop, key, value)) {
00259 xmms_error_set (err, XMMS_ERROR_INVAL, "property could not be set!");
00260 }
00261
00262 x_release_client ();
00263
00264
00265
00266 return (++c->format);
00267 }
00268
00269 static int32_t
00270 xmms_visualization_client_properties_set (xmms_visualization_t *vis, int32_t id, xmmsv_t* prop, xmms_error_t *err)
00271 {
00272 xmms_vis_client_t *c;
00273 xmmsv_dict_iter_t *it;
00274 const gchar *key, *valstr;
00275 xmmsv_t *value;
00276
00277 x_fetch_client (id);
00278
00279 if (!xmmsv_get_type (prop) == XMMSV_TYPE_DICT) {
00280 xmms_error_set (err, XMMS_ERROR_INVAL, "properties must be sent as a dict!");
00281 } else {
00282
00283 xmmsv_get_dict_iter (prop, &it);
00284 while (xmmsv_dict_iter_valid (it)) {
00285 if (!xmmsv_dict_iter_pair (it, &key, &value)) {
00286 xmms_error_set (err, XMMS_ERROR_INVAL, "key-value property pair could not be read!");
00287 } else if (!xmmsv_get_string (value, &valstr)) {
00288 xmms_error_set (err, XMMS_ERROR_INVAL, "property value could not be read!");
00289 } else if (!property_set (&c->prop, key, valstr)) {
00290 xmms_error_set (err, XMMS_ERROR_INVAL, "property could not be set!");
00291 }
00292 xmmsv_dict_iter_next (it);
00293 }
00294
00295 }
00296
00297 x_release_client ();
00298
00299 return (++c->format);
00300 }
00301
00302 static int32_t
00303 xmms_visualization_client_init_shm (xmms_visualization_t *vis, int32_t id, const char *shmidstr, xmms_error_t *err)
00304 {
00305 int shmid;
00306
00307 XMMS_DBG ("Trying to init shm!");
00308
00309 if (sscanf (shmidstr, "%d", &shmid) != 1) {
00310 xmms_error_set (err, XMMS_ERROR_INVAL, "couldn't parse shmid");
00311 return -1;
00312 }
00313 return init_shm (vis, id, shmid, err);
00314 }
00315
00316 static int32_t
00317 xmms_visualization_client_init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
00318 {
00319 XMMS_DBG ("Trying to init udp!");
00320 return init_udp (vis, id, err);
00321 }
00322
00323 static void
00324 xmms_visualization_client_shutdown (xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
00325 {
00326 g_mutex_lock (vis->clientlock);
00327 delete_client (id);
00328 g_mutex_unlock (vis->clientlock);
00329 }
00330
00331 static gboolean
00332 package_write (xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
00333 {
00334 if (c->type == VIS_UNIXSHM) {
00335 return write_shm (&c->transport.shm, c, id, time, channels, size, buf);
00336 } else if (c->type == VIS_UDP) {
00337 return write_udp (&c->transport.udp, c, id, time, channels, size, buf, vis->socket);
00338 }
00339 return FALSE;
00340 }
00341
00342 void
00343 send_data (int channels, int size, short *buf)
00344 {
00345 int i;
00346 struct timeval time;
00347 guint32 latency;
00348
00349 if (!vis) {
00350 return;
00351 }
00352
00353 latency = xmms_output_latency (vis->output);
00354
00355 fft_init ();
00356
00357 gettimeofday (&time, NULL);
00358 time.tv_sec += (latency / 1000);
00359 time.tv_usec += (latency % 1000) * 1000;
00360 if (time.tv_usec > 1000000) {
00361 time.tv_sec++;
00362 time.tv_usec -= 1000000;
00363 }
00364
00365 g_mutex_lock (vis->clientlock);
00366 for (i = 0; i < vis->clientc; ++i) {
00367 if (vis->clientv[i]) {
00368 package_write (vis->clientv[i], i, &time, channels, size, buf);
00369 }
00370 }
00371 g_mutex_unlock (vis->clientlock);
00372 }
00373
00374