21 #include "JackMetadata.h"
23 #include "JackClient.h"
30 #define JACK_METADATA_PREFIX "http://jackaudio.org/metadata/"
38 LIB_EXPORT
const char* JACK_METADATA_PORT_GROUP = JACK_METADATA_PREFIX
"port-group";
41 #undef JACK_METADATA_PREFIX
46 JackMetadata::JackMetadata(
bool isEngine)
48 : fDB(NULL), fDBenv(NULL), fIsEngine(isEngine)
54 JackMetadata::~JackMetadata()
57 char dbpath[PATH_MAX + 1];
64 fDBenv->close (fDBenv, 0);
71 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db/metadata.db", jack_server_dir);
74 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db/__db.001", jack_server_dir);
77 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db/__db.002", jack_server_dir);
80 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db/__db.003", jack_server_dir);
84 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db", jack_server_dir);
90 int JackMetadata::PropertyInit()
95 char dbpath[PATH_MAX + 1];
103 if ((ret = db_env_create (&fDBenv, 0)) != 0) {
104 jack_error (
"cannot initialize DB environment: %s\n", db_strerror (ret));
108 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db", jack_server_dir);
109 mkdir (dbpath, S_IRWXU | S_IRWXG);
111 if ((ret = fDBenv->open (fDBenv, dbpath, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD, 0)) != 0) {
112 jack_error (
"cannot open DB environment: %s", db_strerror (ret));
116 if ((ret = db_create (&fDB, fDBenv, 0)) != 0) {
117 jack_error (
"Cannot initialize metadata DB (%s)", db_strerror (ret));
121 snprintf (dbpath,
sizeof(dbpath),
"%s/jack_db/metadata.db", jack_server_dir);
122 if ((ret = fDB->open (fDB, NULL, dbpath, NULL, DB_HASH, DB_CREATE | DB_THREAD, 0666)) != 0) {
123 jack_error (
"Cannot open metadata DB at %s: %s", dbpath, db_strerror (ret));
136 int JackMetadata::PropertyChangeNotify(JackClient* client, jack_uuid_t subject,
const char* key, jack_property_change_t change)
141 if (client == NULL) {
145 return client->PropertyChangeNotify(subject, key, change);
149 void JackMetadata::MakeKeyDbt(DBT* dbt, jack_uuid_t subject,
const char* key)
151 char ustr[JACK_UUID_STRING_SIZE];
154 memset (dbt, 0,
sizeof(DBT));
155 memset (ustr, 0, JACK_UUID_STRING_SIZE);
156 jack_uuid_unparse (subject, ustr);
157 len1 = JACK_UUID_STRING_SIZE;
158 len2 = strlen (key) + 1;
159 dbt->size = len1 + len2;
160 dbt->data = malloc (dbt->size);
161 memcpy (dbt->data, ustr, len1);
162 memcpy ((
char *)dbt->data + len1, key, len2);
166 int JackMetadata::SetProperty(JackClient* client, jack_uuid_t subject,
const char* key,
const char* value,
const char* type)
174 jack_property_change_t change;
176 if (!key || key[0] ==
'\0') {
177 jack_error (
"empty key string for metadata not allowed");
181 if (!value || value[0] ==
'\0') {
182 jack_error (
"empty value string for metadata not allowed");
186 if (PropertyInit()) {
192 MakeKeyDbt(&d_key, subject, key);
196 memset (&data, 0,
sizeof(data));
198 len1 = strlen (value) + 1;
199 if (type && type[0] !=
'\0') {
200 len2 = strlen (type) + 1;
205 data.size = len1 + len2;
206 data.data = malloc (data.size);
207 memcpy (data.data, value, len1);
210 memcpy ((
char *)data.data + len1, type, len2);
213 if (fDB->exists (fDB, NULL, &d_key, 0) == DB_NOTFOUND) {
214 change = PropertyCreated;
216 change = PropertyChanged;
219 if ((ret = fDB->put (fDB, NULL, &d_key, &data, 0)) != 0) {
220 char ustr[JACK_UUID_STRING_SIZE];
221 jack_uuid_unparse (subject, ustr);
222 jack_error (
"Cannot store metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
223 if (d_key.size > 0) {
232 PropertyChangeNotify(client, subject, key, change);
234 if (d_key.size > 0) {
248 int JackMetadata::GetProperty(jack_uuid_t subject,
const char* key,
char** value,
char** type)
257 if (key == NULL || key[0] ==
'\0') {
261 if (PropertyInit()) {
267 MakeKeyDbt(&d_key, subject, key);
271 memset (&data, 0,
sizeof(data));
272 data.flags = DB_DBT_MALLOC;
274 if ((ret = fDB->get (fDB, NULL, &d_key, &data, 0)) != 0) {
275 if (ret != DB_NOTFOUND) {
276 char ustr[JACK_UUID_STRING_SIZE];
277 jack_uuid_unparse (subject, ustr);
278 jack_error (
"Cannot retrieve metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
280 if (d_key.size > 0) {
296 if (d_key.size > 0) {
305 len1 = strlen ((
const char*)data.data) + 1;
306 (*value) = (
char*)malloc (len1);
307 memcpy (*value, data.data, len1);
309 if (len1 < data.size) {
310 len2 = strlen ((
const char*)data.data + len1) + 1;
312 (*type) = (
char*)malloc (len2);
313 memcpy (*type, (
const char *)data.data + len1, len2);
319 if (d_key.size > 0) {
343 char ustr[JACK_UUID_STRING_SIZE];
344 size_t props_size = 0;
350 memset (ustr, 0, JACK_UUID_STRING_SIZE);
351 jack_uuid_unparse (subject, ustr);
353 if (PropertyInit()) {
358 if ((ret = fDB->cursor (fDB, NULL, &cursor, 0)) != 0) {
359 jack_error (
"Cannot create cursor for metadata search (%s)", db_strerror (ret));
363 memset (&key, 0,
sizeof(key));
364 memset (&data, 0,
sizeof(data));
365 data.flags = DB_DBT_MALLOC;
367 while ((ret = cursor->get (cursor, &key, &data, DB_NEXT)) == 0) {
373 if (key.size < JACK_UUID_STRING_SIZE + 2) {
381 if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
406 if (cnt == props_size) {
407 if (props_size == 0) {
420 jack_uuid_copy (&desc->
subject, subject);
424 len1 = key.size - JACK_UUID_STRING_SIZE;
425 prop->
key = (
char*)malloc (len1);
426 memcpy ((
char*)prop->
key, (
const char *)key.data + JACK_UUID_STRING_SIZE, len1);
432 len1 = strlen ((
const char*)data.data) + 1;
433 prop->
data = (
char*)malloc (len1);
434 memcpy ((
char*)prop->
data, data.data, len1);
436 if (len1 < data.size) {
437 len2 = strlen ((
const char *)data.data + len1) + 1;
439 prop->
type = (
char*)malloc (len2);
440 memcpy ((
char*)prop->
type, (
const char *)data.data + len1, len2);
454 cursor->close (cursor);
476 jack_uuid_t uuid = JACK_UUID_EMPTY_INITIALIZER;
481 if (PropertyInit()) {
485 if ((ret = fDB->cursor (fDB, NULL, &cursor, 0)) != 0) {
486 jack_error (
"Cannot create cursor for metadata search (%s)", db_strerror (ret));
490 memset (&key, 0,
sizeof(key));
491 memset (&data, 0,
sizeof(data));
492 data.flags = DB_DBT_MALLOC;
498 while ((ret = cursor->get (cursor, &key, &data, DB_NEXT)) == 0) {
504 if (key.size < JACK_UUID_STRING_SIZE + 2) {
512 if (jack_uuid_parse ((
const char *)key.data, &uuid) != 0) {
518 for (n = 0; n < dcnt; ++n) {
519 if (jack_uuid_compare (uuid, desc[n].subject) == 0) {
540 jack_uuid_copy (&desc[n].subject, uuid);
544 current_desc = &desc[n];
563 len1 = key.size - JACK_UUID_STRING_SIZE;
564 current_prop->
key = (
char*)malloc (len1);
565 memcpy ((
char*)current_prop->
key, (
const char *)key.data + JACK_UUID_STRING_SIZE, len1);
571 len1 = strlen ((
const char *)data.data) + 1;
572 current_prop->
data = (
char*)malloc (len1);
573 memcpy ((
char*)current_prop->
data, data.data, len1);
575 if (len1 < data.size) {
576 len2 = strlen ((
const char *)data.data + len1) + 1;
578 current_prop->
type = (
char*)malloc (len2);
579 memcpy ((
char*)current_prop->
type, (
const char *)data.data + len1, len2);
582 current_prop->
type = NULL;
591 cursor->close (cursor);
593 (*descriptions) = desc;
612 void JackMetadata::FreeDescription(
jack_description_t* desc,
int free_actual_description_too)
626 if (free_actual_description_too) {
631 int JackMetadata::RemoveProperty(JackClient* client, jack_uuid_t subject,
const char* key)
638 if (PropertyInit()) {
642 MakeKeyDbt(&d_key, subject, key);
643 if ((ret = fDB->del (fDB, NULL, &d_key, 0)) != 0) {
644 jack_error (
"Cannot delete key %s (%s)", key, db_strerror (ret));
645 if (d_key.size > 0) {
651 PropertyChangeNotify(client, subject, key, PropertyDeleted);
653 if (d_key.size > 0) {
664 int JackMetadata::RemoveProperties(JackClient* client, jack_uuid_t subject)
672 char ustr[JACK_UUID_STRING_SIZE];
676 memset (ustr, 0, JACK_UUID_STRING_SIZE);
677 jack_uuid_unparse (subject, ustr);
679 if (PropertyInit() || fDB == NULL) {
683 if ((ret = fDB->cursor (fDB, NULL, &cursor, 0)) != 0) {
684 jack_error (
"Cannot create cursor for metadata search (%s)", db_strerror (ret));
688 memset (&key, 0,
sizeof(key));
689 memset (&data, 0,
sizeof(data));
690 data.flags = DB_DBT_MALLOC;
692 while ((ret = cursor->get (cursor, &key, &data, DB_NEXT)) == 0) {
698 if (key.size < JACK_UUID_STRING_SIZE + 2) {
706 if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
715 if ((ret = cursor->del (cursor, 0)) != 0) {
716 jack_error (
"cannot delete property (%s)", db_strerror (ret));
730 cursor->close (cursor);
733 PropertyChangeNotify(client, subject, NULL, PropertyDeleted);
747 int JackMetadata::RemoveAllProperties(JackClient* client)
752 jack_uuid_t empty_uuid = JACK_UUID_EMPTY_INITIALIZER;
754 if (PropertyInit()) {
758 if ((ret = fDB->truncate (fDB, NULL, NULL, 0)) != 0) {
759 jack_error (
"Cannot clear properties (%s)", db_strerror (ret));
763 PropertyChangeNotify(client, empty_uuid, NULL, PropertyDeleted);
SERVER_EXPORT void jack_error(const char *fmt,...)
jack_property_t * properties