|
楼主 |
发表于 2015-5-9 00:00:58
|
显示全部楼层
支持多连接
本帖最后由 kappa8086 于 2015-5-9 22:13 编辑
市面上的蓝牙音箱或接收器,多数都有一个应用障碍,那就是只允许一个连接,要连接另一设备必须先断开前一个。这是不成熟的特征之一。
诚然我们不会同时使用两个音源(其实也不一定,比如另台设备的系统提示音,来自12306刷票专机什么的),实际使用过多个蓝牙设备却是这种情况——不知道哪个还在连接着,先找到它做断开操作,才能继续。
还有些糟心的东东,比如小米盒子,它关机也不断开蓝牙{:soso_e111:},这时只能登录终端从服务器端干掉它了。
现在我们的系统也是这样,能同时连多种不同的蓝牙设备,但第二个手机或蓝牙耳机准连接不上。
这时bluez系统日志会报:Unable to select SEP。
回看初始化的地方,bluez还记录了两个MediaEndpoint的注册。- May 08 16:12:31 alarm bluetoothd[125]: Endpoint unregistered: sender=:1.3 path=/MediaEndpoint/A2DPSource
- May 08 16:12:31 alarm bluetoothd[125]: Endpoint unregistered: sender=:1.3 path=/MediaEndpoint/A2DPSink1
复制代码 我查了一下,对这两种Endpoint能否支持多个音频流的问题,只有bluez4某版本的changelog有语焉不详的一句,却找不到相应的配置方法。只好又干起了程序猿的本行——读bluez和pulseaudio的源代码。
经过一下午的沉浸,大致理解了两者协作的基本方式,和突破点。
如果无法让一个Endpoint响应多个请求,那最明白的方法就是注册多个,不就ok了么。
解决:
给pulseaudio的bluez模块打个补丁。- mkdir pulseaudio
- cd pulseaudio
- wget https://raw.githubusercontent.com/archlinuxarm/PKGBUILDs/master/extra/pulseaudio/PKGBUILD
复制代码 新建[multi-sink.patch]内容如下- --- /src/pulseaudio-6.0/src/modules/bluetooth/bluez5-util.c 2015-02-12 22:10:35.000000000 +0800
- +++ /src/pulseaudio-6.0/src/modules/bluetooth/bluez5-util.c 2015-05-08 17:50:13.660766952 +0800
- @@ -46,6 +46,7 @@
- #define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
- #define A2DP_SINK_ENDPOINT "/MediaEndpoint/A2DPSink"
- +#define is_sink_endpoint(a) (!strncmp((a), A2DP_SINK_ENDPOINT, strlen(A2DP_SINK_ENDPOINT)))
- #define ENDPOINT_INTROSPECT_XML \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- @@ -820,7 +821,9 @@
- return;
- register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
- - register_endpoint(y, path, A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);
- + register_endpoint(y, path, A2DP_SINK_ENDPOINT "1", PA_BLUETOOTH_UUID_A2DP_SINK);
- + register_endpoint(y, path, A2DP_SINK_ENDPOINT "2", PA_BLUETOOTH_UUID_A2DP_SINK);
- + register_endpoint(y, path, A2DP_SINK_ENDPOINT "3", PA_BLUETOOTH_UUID_A2DP_SINK);
- } else if (pa_streq(interface, BLUEZ_DEVICE_INTERFACE)) {
- @@ -1213,7 +1216,7 @@
- if (pa_streq(endpoint_path, A2DP_SOURCE_ENDPOINT)) {
- if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE))
- p = PA_BLUETOOTH_PROFILE_A2DP_SINK;
- - } else if (pa_streq(endpoint_path, A2DP_SINK_ENDPOINT)) {
- + } else if (is_sink_endpoint(endpoint_path)) {
- if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SINK))
- p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
- }
- @@ -1504,7 +1507,7 @@
- pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
- - if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !pa_streq(path, A2DP_SINK_ENDPOINT))
- + if (!pa_streq(path, A2DP_SOURCE_ENDPOINT) && !is_sink_endpoint(path))
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- @@ -1545,7 +1548,11 @@
- &vtable_endpoint, y));
- break;
- case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
- - pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT,
- + pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "1",
- + &vtable_endpoint, y));
- + pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "2",
- + &vtable_endpoint, y));
- + pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "3",
- &vtable_endpoint, y));
- break;
- default:
- @@ -1562,7 +1569,9 @@
- dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SOURCE_ENDPOINT);
- break;
- case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
- - dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT);
- + dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "1");
- + dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "2");
- + dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), A2DP_SINK_ENDPOINT "3");
- break;
- default:
- pa_assert_not_reached();
复制代码 vim PKGBUILD- arch=(i686 x86_64 armv7h) #给arch增加一个armv7h,搞毛啊,arm专用的PKGBUILD里只有i686 x86_64
复制代码 prepare() 函数里第一句前加上- git apply multi-sink.patch
复制代码 makepkg 一下,去烧壶水喝杯茶。有点耗时,然而最终我们只需要libbluez5-util.so- strip -s src/pulseaudio-6.0/src/.libs/libbluez5-util.so
- sudo cp src/pulseaudio-6.0/src/.libs/libbluez5-util.so /usr/lib/pulse-6.0/modules/libbluez5-util.so #注意先备份
复制代码 重启一下pulseaudio,顺利的话(的确比我想像的还顺利),journalctl 会看到原来的两个Endpoint变成了- May 08 18:12:32 alarm bluetoothd[125]: Endpoint registered: sender=:1.19 path=/MediaEndpoint/A2DPSource
- May 08 18:12:32 alarm bluetoothd[125]: Endpoint registered: sender=:1.19 path=/MediaEndpoint/A2DPSink1
- May 08 18:12:33 alarm bluetoothd[125]: Endpoint registered: sender=:1.19 path=/MediaEndpoint/A2DPSink2
- May 08 18:12:33 alarm bluetoothd[125]: Endpoint registered: sender=:1.19 path=/MediaEndpoint/A2DPSink3
复制代码 然后试试两个以上手机/平板同时连上去。
现在这个系统可以支持最多三个设备同时连接了,还可以同时发声哦~ 市面上没几个蓝牙音箱产品能做到这一点{:soso_e104:}
然而不幸的是pulseaudio的崩溃几率也增加了{:soso_e134:}
为可靠性考虑,也得把pulseaudio服务控制起来。
[/etc/systemd/system/pulseaudio@.service]- [Unit]
- Description=Pulseaudio service
- [Service]
- User=%i
- ExecStart=/usr/bin/pulseaudio
- Restart=always
- LimitRTPRIO=65
- LimitNICE=-10
- LimitMEMLOCK=40000
- [Install]
- WantedBy=multi-user.target
复制代码 systemctl enable pulseaudio@audioman
如果连接断了,说明pulseaudio挂了,它会自动重启,让设备重新连接一下。
|
|