This also fixes the issue that the old code generated form factors that were not in line with the PA_PROP_DEVICE_FORM_FACTOR documentation. --- src/modules/bluetooth/bluetooth-util.c | 72 ++++++++----------- src/modules/bluetooth/bluetooth-util.h | 16 +---- src/modules/bluetooth/module-bluetooth-device.c | 91 ++++++++++--------------- src/pulsecore/device-class.c | 19 ++++++ src/pulsecore/device-class.h | 18 +++++ 5 files changed, 103 insertions(+), 113 deletions(-) diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 5924736..c5b070c 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -2171,19 +2171,30 @@ pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hoo return &y->hooks[hook]; } -pa_bt_form_factor_t pa_bluetooth_get_form_factor(uint32_t class) { +pa_device_class_t pa_bluetooth_convert_device_class(uint32_t class) { unsigned major, minor; - pa_bt_form_factor_t r; - - static const pa_bt_form_factor_t table[] = { - [1] = PA_BT_FORM_FACTOR_HEADSET, - [2] = PA_BT_FORM_FACTOR_HANDSFREE, - [4] = PA_BT_FORM_FACTOR_MICROPHONE, - [5] = PA_BT_FORM_FACTOR_SPEAKER, - [6] = PA_BT_FORM_FACTOR_HEADPHONE, - [7] = PA_BT_FORM_FACTOR_PORTABLE, - [8] = PA_BT_FORM_FACTOR_CAR, - [10] = PA_BT_FORM_FACTOR_HIFI + pa_device_class_t r; + + static const pa_device_class_t table[] = { + [0] = PA_DEVICE_CLASS_UNKNOWN, + [1] = PA_DEVICE_CLASS_HEADSET, + [2] = PA_DEVICE_CLASS_HANDSFREE, + [3] = PA_DEVICE_CLASS_UNKNOWN, + [4] = PA_DEVICE_CLASS_MICROPHONE, + [5] = PA_DEVICE_CLASS_SPEAKERS, + [6] = PA_DEVICE_CLASS_HEADPHONES, + [7] = PA_DEVICE_CLASS_PORTABLE, + [8] = PA_DEVICE_CLASS_CAR, + [9] = PA_DEVICE_CLASS_SETTOP_BOX, + [10] = PA_DEVICE_CLASS_HIFI, + [11] = PA_DEVICE_CLASS_VCR, + [12] = PA_DEVICE_CLASS_VIDEO_CAMERA, + [13] = PA_DEVICE_CLASS_CAMCORDER, + [14] = PA_DEVICE_CLASS_UNKNOWN, + [15] = PA_DEVICE_CLASS_VIDEO_DISPLAY_AND_SPEAKERS, + [16] = PA_DEVICE_CLASS_VIDEO_CONFERENCING, + [17] = PA_DEVICE_CLASS_UNKNOWN, + [18] = PA_DEVICE_CLASS_GAMING_OR_TOY }; /* @@ -2194,50 +2205,25 @@ pa_bt_form_factor_t pa_bluetooth_get_form_factor(uint32_t class) { minor = (class >> 2) & 0x3F; switch (major) { + case 1: + return PA_DEVICE_CLASS_COMPUTER; case 2: - return PA_BT_FORM_FACTOR_PHONE; + return PA_DEVICE_CLASS_PHONE; case 4: break; default: pa_log_debug("Unknown Bluetooth major device class %u", major); - return PA_BT_FORM_FACTOR_UNKNOWN; + return PA_DEVICE_CLASS_UNKNOWN; } - r = minor < PA_ELEMENTSOF(table) ? table[minor] : PA_BT_FORM_FACTOR_UNKNOWN; + r = minor < PA_ELEMENTSOF(table) ? table[minor] : PA_DEVICE_CLASS_UNKNOWN; - if (!r) + if (r == PA_DEVICE_CLASS_UNKNOWN) pa_log_debug("Unknown Bluetooth minor device class %u", minor); return r; } -const char *pa_bt_form_factor_to_string(pa_bt_form_factor_t ff) { - switch (ff) { - case PA_BT_FORM_FACTOR_UNKNOWN: - return "unknown"; - case PA_BT_FORM_FACTOR_HEADSET: - return "headset"; - case PA_BT_FORM_FACTOR_HANDSFREE: - return "hands-free"; - case PA_BT_FORM_FACTOR_MICROPHONE: - return "microphone"; - case PA_BT_FORM_FACTOR_SPEAKER: - return "speaker"; - case PA_BT_FORM_FACTOR_HEADPHONE: - return "headphone"; - case PA_BT_FORM_FACTOR_PORTABLE: - return "portable"; - case PA_BT_FORM_FACTOR_CAR: - return "car"; - case PA_BT_FORM_FACTOR_HIFI: - return "hifi"; - case PA_BT_FORM_FACTOR_PHONE: - return "phone"; - } - - pa_assert_not_reached(); -} - char *pa_bluetooth_cleanup_name(const char *name) { char *t, *s, *d; bool space = false; diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index 3361b0f..b7842af 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -154,21 +154,7 @@ void pa_bluetooth_transport_set_speaker_gain(pa_bluetooth_transport *t, uint16_t pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hook_t hook); -typedef enum pa_bt_form_factor { - PA_BT_FORM_FACTOR_UNKNOWN, - PA_BT_FORM_FACTOR_HEADSET, - PA_BT_FORM_FACTOR_HANDSFREE, - PA_BT_FORM_FACTOR_MICROPHONE, - PA_BT_FORM_FACTOR_SPEAKER, - PA_BT_FORM_FACTOR_HEADPHONE, - PA_BT_FORM_FACTOR_PORTABLE, - PA_BT_FORM_FACTOR_CAR, - PA_BT_FORM_FACTOR_HIFI, - PA_BT_FORM_FACTOR_PHONE, -} pa_bt_form_factor_t; - -pa_bt_form_factor_t pa_bluetooth_get_form_factor(uint32_t class); -const char *pa_bt_form_factor_to_string(pa_bt_form_factor_t ff); +pa_device_class_t pa_bluetooth_convert_device_class(uint32_t class); char *pa_bluetooth_cleanup_name(const char *name); diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index a517e59..aadc260 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -2063,6 +2063,7 @@ off: /* Run from main thread */ static void create_card_ports(struct userdata *u, pa_hashmap *ports) { + pa_device_class_t device_class; pa_device_port *port; pa_device_port_new_data port_data; @@ -2070,62 +2071,42 @@ static void create_card_ports(struct userdata *u, pa_hashmap *ports) { const char *input_description = NULL; const char *output_description = NULL; + static const char *input_description_table[PA_DEVICE_CLASS_MAX] = { + [PA_DEVICE_CLASS_HEADSET] = N_("Headset"), + [PA_DEVICE_CLASS_HANDSFREE] = N_("Hands-free"), + [PA_DEVICE_CLASS_MICROPHONE] = N_("Microphone"), + [PA_DEVICE_CLASS_PORTABLE] = N_("Portable"), + [PA_DEVICE_CLASS_CAR] = N_("Car"), + [PA_DEVICE_CLASS_SETTOP_BOX] = N_("Set-top Box"), + [PA_DEVICE_CLASS_HIFI] = N_("HiFi"), + [PA_DEVICE_CLASS_VCR] = N_("VCR"), + [PA_DEVICE_CLASS_VIDEO_CAMERA] = N_("Video Camera"), + [PA_DEVICE_CLASS_CAMCORDER] = N_("Camcorder"), + [PA_DEVICE_CLASS_VIDEO_CONFERENCING] = N_("Video Conferencing") + }; + + static const char *output_description_table[PA_DEVICE_CLASS_MAX] = { + [PA_DEVICE_CLASS_HEADSET] = N_("Headset"), + [PA_DEVICE_CLASS_HANDSFREE] = N_("Hands-free"), + [PA_DEVICE_CLASS_SPEAKERS] = N_("Speakers"), + [PA_DEVICE_CLASS_HEADPHONES] = N_("Headphones"), + [PA_DEVICE_CLASS_PORTABLE] = N_("Portable"), + [PA_DEVICE_CLASS_CAR] = N_("Car"), + [PA_DEVICE_CLASS_SETTOP_BOX] = N_("Set-top Box"), + [PA_DEVICE_CLASS_HIFI] = N_("HiFi"), + [PA_DEVICE_CLASS_VCR] = N_("VCR"), + [PA_DEVICE_CLASS_VIDEO_DISPLAY_AND_SPEAKERS] = N_("Video Display and Speakers"), + [PA_DEVICE_CLASS_VIDEO_CONFERENCING] = N_("Video Conferencing") + }; + pa_assert(u); pa_assert(ports); pa_assert(u->device); - switch (pa_bluetooth_get_form_factor(u->device->class)) { - case PA_BT_FORM_FACTOR_UNKNOWN: - break; - - case PA_BT_FORM_FACTOR_HEADSET: - name_prefix = "headset"; - input_description = output_description = _("Headset"); - break; - - case PA_BT_FORM_FACTOR_HANDSFREE: - name_prefix = "handsfree"; - input_description = output_description = _("Handsfree"); - break; - - case PA_BT_FORM_FACTOR_MICROPHONE: - name_prefix = "microphone"; - input_description = _("Microphone"); - break; - - case PA_BT_FORM_FACTOR_SPEAKER: - name_prefix = "speaker"; - output_description = _("Speaker"); - break; - - case PA_BT_FORM_FACTOR_HEADPHONE: - name_prefix = "headphone"; - output_description = _("Headphone"); - break; - - case PA_BT_FORM_FACTOR_PORTABLE: - name_prefix = "portable"; - input_description = output_description = _("Portable"); - break; - - case PA_BT_FORM_FACTOR_CAR: - name_prefix = "car"; - input_description = output_description = _("Car"); - break; - - case PA_BT_FORM_FACTOR_HIFI: - name_prefix = "hifi"; - input_description = output_description = _("HiFi"); - break; - - case PA_BT_FORM_FACTOR_PHONE: - name_prefix = "phone"; - input_description = output_description = _("Phone"); - break; - } - - if (!name_prefix) - name_prefix = "unknown"; + device_class = pa_bluetooth_convert_device_class(u->device->class); + name_prefix = pa_device_class_to_string(device_class); + input_description = input_description_table[device_class]; + output_description = output_description_table[device_class]; if (!output_description) output_description = _("Bluetooth Output"); @@ -2230,8 +2211,8 @@ static int add_card(struct userdata *u) { bool b; pa_card_profile *p; enum profile *d; - pa_bt_form_factor_t ff; char *n; + const char *form_factor; const char *default_profile; const pa_bluetooth_device *device; const pa_bluetooth_uuid *uuid; @@ -2253,8 +2234,8 @@ static int add_card(struct userdata *u) { pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth"); - if ((ff = pa_bluetooth_get_form_factor(device->class)) != PA_BT_FORM_FACTOR_UNKNOWN) - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, pa_bt_form_factor_to_string(ff)); + if ((form_factor = pa_device_class_to_form_factor_string(pa_bluetooth_convert_device_class(device->class)))) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, form_factor); pa_proplist_sets(data.proplist, "bluez.path", device->path); pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) device->class); diff --git a/src/pulsecore/device-class.c b/src/pulsecore/device-class.c index 73f20ae..4b90992 100644 --- a/src/pulsecore/device-class.c +++ b/src/pulsecore/device-class.c @@ -51,6 +51,21 @@ static const char * const string_table[PA_DEVICE_CLASS_MAX] = { [PA_DEVICE_CLASS_TUNER] = "tuner" }; +static const char * const form_factor_table[PA_DEVICE_CLASS_MAX] = { + [PA_DEVICE_CLASS_COMPUTER] = "computer", + [PA_DEVICE_CLASS_PHONE] = "handset", + [PA_DEVICE_CLASS_HEADSET] = "headset", + [PA_DEVICE_CLASS_HANDSFREE] = "hands-free", + [PA_DEVICE_CLASS_MICROPHONE] = "microphone", + [PA_DEVICE_CLASS_SPEAKERS] = "speaker", + [PA_DEVICE_CLASS_HEADPHONES] = "headphone", + [PA_DEVICE_CLASS_PORTABLE] = "portable", + [PA_DEVICE_CLASS_CAR] = "car", + [PA_DEVICE_CLASS_HIFI] = "hifi", + [PA_DEVICE_CLASS_VIDEO_CAMERA] = "webcam", + [PA_DEVICE_CLASS_VIDEO_DISPLAY_AND_SPEAKERS] = "tv" +}; + pa_device_class_t pa_device_class_from_string(const char *str) { unsigned i; @@ -67,3 +82,7 @@ pa_device_class_t pa_device_class_from_string(const char *str) { const char *pa_device_class_to_string(pa_device_class_t class) { return string_table[class]; } + +const char *pa_device_class_to_form_factor_string(pa_device_class_t class) { + return form_factor_table[class]; +} diff --git a/src/pulsecore/device-class.h b/src/pulsecore/device-class.h index e820fc2..a459db2 100644 --- a/src/pulsecore/device-class.h +++ b/src/pulsecore/device-class.h @@ -67,4 +67,22 @@ typedef enum { pa_device_class_t pa_device_class_from_string(const char *str); const char *pa_device_class_to_string(pa_device_class_t class); +/* This function produces a string that is suitable to be used as the + * PA_PROP_DEVICE_FORM_FACTOR property. Not all device classes are suitable, + * because the documentation for the property defines a fixed list of possible + * values, and that list doesn't contain all the device classes that we have + * available. If the device class can't be converted to one of the listed form + * factors, this function returns NULL. + * + * We possibly could change the documentation of the DEVICE_FORM_FACTOR + * property, but that would be strictly speaking an ABI break. Also, it's quite + * nice to have a device class enumeration that isn't exposed to clients, + * because it allows us to easily tune the enumeration contents without + * worrying about client compatibility, so I'm not eager to force the device + * class enumeration to be the same thing as the form factor property, even if + * they are pretty similar (also note that they may be similar, but definitely + * not the same thing, because e.g. "tuner" is a valid device class, but not a + * form factor). */ +const char *pa_device_class_to_form_factor_string(pa_device_class_t class); + #endif -- 1.8.1.2