summaryrefslogtreecommitdiffstats
path: root/spa/plugins/bluez5/media-codecs.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--spa/plugins/bluez5/media-codecs.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/spa/plugins/bluez5/media-codecs.c b/spa/plugins/bluez5/media-codecs.c
new file mode 100644
index 0000000..28445fc
--- /dev/null
+++ b/spa/plugins/bluez5/media-codecs.c
@@ -0,0 +1,212 @@
+/*
+ * BlueALSA - bluez-a2dp.c
+ * Copyright (c) 2016-2017 Arkadiusz Bokowy
+ *
+ * This file is a part of bluez-alsa.
+ *
+ * This project is licensed under the terms of the MIT license.
+ *
+ */
+
+#include <spa/utils/string.h>
+
+#include "media-codecs.h"
+
+int media_codec_select_config(const struct media_codec_config configs[], size_t n,
+ uint32_t cap, int preferred_value)
+{
+ size_t i;
+ int *scores, res;
+ unsigned int max_priority;
+
+ if (n == 0)
+ return -EINVAL;
+
+ scores = calloc(n, sizeof(int));
+ if (scores == NULL)
+ return -errno;
+
+ max_priority = configs[0].priority;
+ for (i = 1; i < n; ++i) {
+ if (configs[i].priority > max_priority)
+ max_priority = configs[i].priority;
+ }
+
+ for (i = 0; i < n; ++i) {
+ if (!(configs[i].config & cap)) {
+ scores[i] = -1;
+ continue;
+ }
+ if (configs[i].value == preferred_value)
+ scores[i] = 100 * (max_priority + 1);
+ else if (configs[i].value > preferred_value)
+ scores[i] = 10 * (max_priority + 1);
+ else
+ scores[i] = 1;
+
+ scores[i] *= configs[i].priority + 1;
+ }
+
+ res = 0;
+ for (i = 1; i < n; ++i) {
+ if (scores[i] > scores[res])
+ res = i;
+ }
+
+ if (scores[res] < 0)
+ res = -EINVAL;
+
+ free(scores);
+ return res;
+}
+
+bool media_codec_check_caps(const struct media_codec *codec, unsigned int codec_id,
+ const void *caps, size_t caps_size,
+ const struct media_codec_audio_info *info,
+ const struct spa_dict *global_settings)
+{
+ uint8_t config[A2DP_MAX_CAPS_SIZE];
+ int res;
+
+ if (codec_id != codec->codec_id)
+ return false;
+
+ if (caps == NULL)
+ return false;
+
+ res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config);
+ if (res < 0)
+ return false;
+
+ if (codec->bap)
+ return true;
+ else
+ return ((size_t)res == caps_size);
+}
+
+#ifdef CODEC_PLUGIN
+
+struct impl {
+ struct spa_handle handle;
+ struct spa_bluez5_codec_a2dp bluez5_codec_a2dp;
+};
+
+static int
+impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
+{
+ struct impl *this;
+
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
+ spa_return_val_if_fail(interface != NULL, -EINVAL);
+
+ this = (struct impl *) handle;
+
+ if (spa_streq(type, SPA_TYPE_INTERFACE_Bluez5CodecMedia))
+ *interface = &this->bluez5_codec_a2dp;
+ else
+ return -ENOENT;
+
+ return 0;
+}
+
+static int
+impl_clear(struct spa_handle *handle)
+{
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
+ return 0;
+}
+
+static size_t
+impl_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params)
+{
+ return sizeof(struct impl);
+}
+
+static int
+impl_init(const struct spa_handle_factory *factory,
+ struct spa_handle *handle,
+ const struct spa_dict *info,
+ const struct spa_support *support,
+ uint32_t n_support)
+{
+ struct impl *this;
+
+ spa_return_val_if_fail(factory != NULL, -EINVAL);
+ spa_return_val_if_fail(handle != NULL, -EINVAL);
+
+ handle->get_interface = impl_get_interface;
+ handle->clear = impl_clear;
+
+ this = (struct impl *) handle;
+
+ this->bluez5_codec_a2dp.codecs = codec_plugin_media_codecs;
+ this->bluez5_codec_a2dp.iface = SPA_INTERFACE_INIT(
+ SPA_TYPE_INTERFACE_Bluez5CodecMedia,
+ SPA_VERSION_BLUEZ5_CODEC_MEDIA,
+ NULL,
+ this);
+
+ return 0;
+}
+
+static const struct spa_interface_info impl_interfaces[] = {
+ {SPA_TYPE_INTERFACE_Bluez5CodecMedia,},
+};
+
+static int
+impl_enum_interface_info(const struct spa_handle_factory *factory,
+ const struct spa_interface_info **info,
+ uint32_t *index)
+{
+ spa_return_val_if_fail(factory != NULL, -EINVAL);
+ spa_return_val_if_fail(info != NULL, -EINVAL);
+ spa_return_val_if_fail(index != NULL, -EINVAL);
+
+ switch (*index) {
+ case 0:
+ *info = &impl_interfaces[*index];
+ break;
+ default:
+ return 0;
+ }
+ (*index)++;
+
+ return 1;
+}
+
+static const struct spa_dict_item handle_info_items[] = {
+ { SPA_KEY_FACTORY_DESCRIPTION, "Bluetooth codec plugin" },
+};
+
+static const struct spa_dict handle_info = SPA_DICT_INIT_ARRAY(handle_info_items);
+
+static struct spa_handle_factory handle_factory = {
+ SPA_VERSION_HANDLE_FACTORY,
+ NULL,
+ &handle_info,
+ impl_get_size,
+ impl_init,
+ impl_enum_interface_info,
+};
+
+SPA_EXPORT
+int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index)
+{
+ spa_return_val_if_fail(factory != NULL, -EINVAL);
+ spa_return_val_if_fail(index != NULL, -EINVAL);
+
+ if (handle_factory.name == NULL)
+ handle_factory.name = codec_plugin_factory_name;
+
+ switch (*index) {
+ case 0:
+ *factory = &handle_factory;
+ break;
+ default:
+ return 0;
+ }
+ (*index)++;
+ return 1;
+}
+
+#endif