Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
art.c
Go to the documentation of this file.
1 /*
2  * art.c
3  * Copyright 2011-2012 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <assert.h>
21 #include <errno.h>
22 #include <glib.h>
23 #include <pthread.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include <libaudcore/audstrings.h>
30 #include <libaudcore/hook.h>
31 
32 #include "main.h"
33 #include "misc.h"
34 #include "playlist.h"
35 #include "scanner.h"
36 #include "util.h"
37 
38 #define FLAG_DONE 1
39 #define FLAG_SENT 2
40 
41 typedef struct {
42  int refcount;
43  int flag;
44 
45  /* album art as JPEG or PNG data */
46  void * data;
47  int64_t len;
48 
49  /* album art as (possibly a temporary) file */
50  char * art_file;
52 } ArtItem;
53 
54 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
55 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
56 
57 static GHashTable * art_items; /* of ArtItem */
58 static char * current_ref; /* pooled */
59 static int send_source;
60 
61 static void art_item_free (ArtItem * item)
62 {
63  /* delete temporary file */
64  if (item->art_file && item->is_temp)
65  {
66  char * unixname = uri_to_filename (item->art_file);
67  if (unixname)
68  {
69  unlink (unixname);
70  free (unixname);
71  }
72  }
73 
74  free (item->data);
75  free (item->art_file);
76  g_slice_free (ArtItem, item);
77 }
78 
79 static bool_t send_requests (void * unused)
80 {
81  pthread_mutex_lock (& mutex);
82 
83  GQueue queue = G_QUEUE_INIT;
84 
85  GHashTableIter iter;
86  void * ptr1, * ptr2;
87 
88  g_hash_table_iter_init (& iter, art_items);
89  while (g_hash_table_iter_next (& iter, & ptr1, & ptr2))
90  {
91  char * file = ptr1;
92  ArtItem * item = ptr2;
93 
94  if (item->flag == FLAG_DONE)
95  {
96  g_queue_push_tail (& queue, str_ref (file));
97  item->flag = FLAG_SENT;
98  }
99  }
100 
101  if (send_source)
102  {
103  g_source_remove (send_source);
104  send_source = 0;
105  }
106 
107  pthread_mutex_unlock (& mutex);
108 
109  char * current = NULL;
110  if (! current_ref)
111  current = playback_entry_get_filename ();
112 
113  char * file;
114  while ((file = g_queue_pop_head (& queue)))
115  {
116  hook_call ("art ready", file);
117 
118  if (current && ! strcmp (file, current))
119  {
120  hook_call ("current art ready", file);
121  current_ref = file;
122  }
123  else
124  {
125  art_unref (file); /* release temporary reference */
126  str_unref (file);
127  }
128  }
129 
130  str_unref (current);
131  return FALSE;
132 }
133 
134 static void request_callback (ScanRequest * request)
135 {
136  pthread_mutex_lock (& mutex);
137 
138  const char * file = scan_request_get_filename (request);
139  ArtItem * item = g_hash_table_lookup (art_items, file);
140  assert (item != NULL && ! item->flag);
141 
142  scan_request_get_image_data (request, & item->data, & item->len);
143  item->art_file = scan_request_get_image_file (request);
144  item->flag = FLAG_DONE;
145 
146  if (! send_source)
147  send_source = g_idle_add (send_requests, NULL);
148 
149  pthread_cond_broadcast (& cond);
150  pthread_mutex_unlock (& mutex);
151 }
152 
153 static ArtItem * art_item_get (const char * file, bool_t blocking)
154 {
155  ArtItem * item = g_hash_table_lookup (art_items, file);
156 
157  if (item && item->flag)
158  {
159  item->refcount ++;
160  return item;
161  }
162 
163  if (! item)
164  {
165  item = g_slice_new0 (ArtItem);
166  g_hash_table_insert (art_items, str_get (file), item);
167  item->refcount = 1; /* temporary reference */
168 
170  }
171 
172  if (! blocking)
173  return NULL;
174 
175  item->refcount ++;
176 
177  while (! item->flag)
178  pthread_cond_wait (& cond, & mutex);
179 
180  return item;
181 }
182 
183 static void art_item_unref (const char * file, ArtItem * item)
184 {
185  if (! -- item->refcount)
186  g_hash_table_remove (art_items, file);
187 }
188 
189 static void release_current (void)
190 {
191  if (current_ref)
192  {
195  current_ref = NULL;
196  }
197 }
198 
199 void art_init (void)
200 {
201  art_items = g_hash_table_new_full (g_str_hash, g_str_equal,
202  (GDestroyNotify) str_unref, (GDestroyNotify) art_item_free);
203 
204  hook_associate ("playlist position", (HookFunction) release_current, NULL);
205  hook_associate ("playlist set playing", (HookFunction) release_current, NULL);
206 }
207 
208 void art_cleanup (void)
209 {
210  hook_dissociate ("playlist position", (HookFunction) release_current);
211  hook_dissociate ("playlist set playing", (HookFunction) release_current);
212 
213  if (send_source)
214  {
215  g_source_remove (send_source);
216  send_source = 0;
217  }
218 
219  release_current ();
220 
221  g_hash_table_destroy (art_items);
222  art_items = NULL;
223 }
224 
225 void art_get_data_real (const char * file, const void * * data, int64_t * len,
226  bool_t blocking)
227 {
228  * data = NULL;
229  * len = 0;
230 
231  pthread_mutex_lock (& mutex);
232 
233  ArtItem * item = art_item_get (file, blocking);
234  if (! item)
235  goto UNLOCK;
236 
237  /* load data from external image file */
238  if (! item->data && item->art_file)
239  vfs_file_get_contents (item->art_file, & item->data, & item->len);
240 
241  if (item->data)
242  {
243  * data = item->data;
244  * len = item->len;
245  }
246  else
247  art_item_unref (file, item);
248 
249 UNLOCK:
250  pthread_mutex_unlock (& mutex);
251 }
252 
253 const char * art_get_file_real (const char * file, bool_t blocking)
254 {
255  const char * art_file = NULL;
256  pthread_mutex_lock (& mutex);
257 
258  ArtItem * item = art_item_get (file, blocking);
259  if (! item)
260  goto UNLOCK;
261 
262  /* save data to temporary file */
263  if (item->data && ! item->art_file)
264  {
265  char * unixname = write_temp_file (item->data, item->len);
266  if (unixname)
267  {
268  item->art_file = filename_to_uri (unixname);
269  item->is_temp = TRUE;
270  free (unixname);
271  }
272  }
273 
274  if (item->art_file)
275  art_file = item->art_file;
276  else
277  art_item_unref (file, item);
278 
279 UNLOCK:
280  pthread_mutex_unlock (& mutex);
281  return art_file;
282 }
283 
284 void art_request_data (const char * file, const void * * data, int64_t * len)
285 {
286  return art_get_data_real (file, data, len, FALSE);
287 }
288 
289 const char * art_request_file (const char * file)
290 {
291  return art_get_file_real (file, FALSE);
292 }
293 
294 void art_get_data (const char * file, const void * * data, int64_t * len)
295 {
296  fprintf (stderr, "aud_art_get_data() is deprecated. Use "
297  "aud_art_request_data() instead.\n");
298  return art_get_data_real (file, data, len, TRUE);
299 }
300 
301 const char * art_get_file (const char * file)
302 {
303  fprintf (stderr, "aud_art_get_file() is deprecated. Use "
304  "aud_art_request_file() instead.\n");
305  return art_get_file_real (file, TRUE);
306 }
307 
308 void art_unref (const char * file)
309 {
310  pthread_mutex_lock (& mutex);
311 
312  ArtItem * item = g_hash_table_lookup (art_items, file);
313  assert (item != NULL);
314 
315  art_item_unref (file, item);
316 
317  pthread_mutex_unlock (& mutex);
318 }
#define FLAG_DONE
Definition: art.c:38
void art_get_data(const char *file, const void **data, int64_t *len)
Definition: art.c:294
void art_request_data(const char *file, const void **data, int64_t *len)
Definition: art.c:284
char * write_temp_file(void *data, int64_t len)
Definition: util.c:118
char * art_file
Definition: art.c:50
int flag
Definition: art.c:43
static void art_item_free(ArtItem *item)
Definition: art.c:61
#define SCAN_IMAGE
Definition: scanner.h:27
EXPORT char * uri_to_filename(const char *uri)
Definition: audstrings.c:172
const char * art_get_file(const char *file)
Definition: art.c:301
const char * scan_request_get_filename(ScanRequest *request)
Definition: scanner.c:122
void art_get_data_real(const char *file, const void **data, int64_t *len, bool_t blocking)
Definition: art.c:225
char * playback_entry_get_filename(void)
void(* HookFunction)(void *data, void *user)
Definition: hook.h:23
EXPORT void hook_associate(const char *name, HookFunction func, void *user)
Definition: hook.c:36
#define FALSE
Definition: core.h:35
static void release_current(void)
Definition: art.c:189
Index Index bool_t
Definition: playlist-api.h:122
#define hook_dissociate(n, f)
Definition: hook.h:34
char * str_ref(char *str)
Definition: strpool.c:74
void art_unref(const char *file)
Definition: art.c:308
int refcount
Definition: art.c:42
static char * current_ref
Definition: art.c:58
#define NULL
Definition: core.h:27
bool_t is_temp
Definition: art.c:51
ScanRequest * scan_request(const char *filename, int flags, PluginHandle *decoder, ScanCallback callback)
Definition: scanner.c:51
void scan_request_get_image_data(ScanRequest *request, void **data, int64_t *len)
Definition: scanner.c:139
void * data
Definition: art.c:46
#define TRUE
Definition: core.h:37
static ArtItem * art_item_get(const char *file, bool_t blocking)
Definition: art.c:153
static void request_callback(ScanRequest *request)
Definition: art.c:134
static GHashTable * art_items
Definition: art.c:57
void str_unref(char *str)
Definition: strpool.c:89
static pthread_cond_t cond
Definition: art.c:55
void vfs_file_get_contents(const char *filename, void **buf, int64_t *size)
Gets contents of the file into a buffer.
Definition: vfs_common.c:149
char * scan_request_get_image_file(ScanRequest *request)
Definition: scanner.c:147
static pthread_mutex_t mutex
Definition: art.c:54
Definition: art.c:41
#define FLAG_SENT
Definition: art.c:39
EXPORT void hook_call(const char *name, void *data)
Definition: hook.c:98
void art_init(void)
Definition: art.c:199
static void art_item_unref(const char *file, ArtItem *item)
Definition: art.c:183
void art_cleanup(void)
Definition: art.c:208
static bool_t send_requests(void *unused)
Definition: art.c:79
EXPORT char * filename_to_uri(const char *name)
Definition: audstrings.c:143
const char * art_request_file(const char *file)
Definition: art.c:289
static int send_source
Definition: art.c:59
const char * art_get_file_real(const char *file, bool_t blocking)
Definition: art.c:253
char * str_get(const char *str)
Definition: strpool.c:42
int64_t len
Definition: art.c:47