• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/xmms/visualization/object.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
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 /** @defgroup Visualization Visualization
00028   * @ingroup XMMSServer
00029   * @brief Feeds playing data in various forms to the client.
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 /* create an uninitialised vis client. don't use this method without mutex! */
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 /* delete a vis client. don't use this method without mutex! */
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  * Initialize the Vis module.
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  * Free all resoures used by visualization module.
00145  * TODO: Fill this in properly, unregister etc!
00146  */
00147 
00148 void
00149 xmms_visualization_destroy ()
00150 {
00151     /* TODO: assure that the xform is already dead! */
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         /* it seems there is no way to remove the watch */
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     /* if there is a way to disable visualization support on the server side,
00170        we could return 0 here, or we could return an error? */
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     /* TODO: all the stuff following */
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         /* do necessary initialisations here */
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     /* the format identifier (between client and server) changes. so the client can recognize the first packet
00249        which is built using the new format according to the newly set property */
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         /* record every pair */
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         /* TODO: propagate new format to xform! */
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 /** @} */

Generated on Wed Feb 9 2011 for XMMS2 by  doxygen 1.7.1