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