├── recipes-connectivity ├── bluez5 │ ├── files │ │ └── main.conf │ └── bluez5_5.54.bbappend └── a2dp-agent │ ├── files │ ├── a2dp-agent.sh │ └── agent.c │ └── a2dp-agent.bb ├── recipes-core ├── init-ifupdown │ └── init-ifupdown_1.0.bbappend ├── initscripts │ ├── initscripts_1.0.bbappend │ └── files │ │ └── mountall.sh ├── dac-config │ ├── files │ │ ├── autoconnect.sh │ │ └── bt-init.sh │ └── dac-config.bb └── images │ └── core-image-base.bbappend ├── recipes-kernel └── linux │ ├── linux-raspberrypi_5.4.bbappend │ └── files │ └── fragment.cfg ├── recipes-bsp └── bootfiles │ └── rpi-config_git.bbappend ├── recipes-multimedia ├── bluez-alsa │ ├── files │ │ └── bluealsa.sh │ └── bluez-alsa_3.0.0.bb └── fdk-aac │ └── fdk-aac_2.0.1.bb ├── conf └── layer.conf ├── LICENSE └── README.md /recipes-connectivity/bluez5/files/main.conf: -------------------------------------------------------------------------------- 1 | [General] 2 | Name=RPi-DAC 3 | DiscoverableTimeout=0 4 | 5 | -------------------------------------------------------------------------------- /recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend: -------------------------------------------------------------------------------- 1 | INITSCRIPT_PARAMS = "start 01 . stop 80 0 6 1 ." 2 | -------------------------------------------------------------------------------- /recipes-kernel/linux/linux-raspberrypi_5.4.bbappend: -------------------------------------------------------------------------------- 1 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" 2 | SRC_URI += "file://fragment.cfg" 3 | 4 | DEPENDS += "lz4-native" 5 | 6 | -------------------------------------------------------------------------------- /recipes-core/initscripts/initscripts_1.0.bbappend: -------------------------------------------------------------------------------- 1 | 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" 3 | 4 | do_install_append () { 5 | update-rc.d -f -r ${D} mountnfs.sh remove 6 | update-rc.d -f -r ${D} read-only-rootfs-hook.sh remove 7 | } 8 | 9 | -------------------------------------------------------------------------------- /recipes-bsp/bootfiles/rpi-config_git.bbappend: -------------------------------------------------------------------------------- 1 | ENABLE_UART = "1" 2 | 3 | do_deploy_append_raspberrypi0-wifi() { 4 | echo "# DAC device tree overlay" >> ${DEPLOYDIR}/bootfiles/config.txt 5 | echo "dtoverlay=hifiberry-dac" >> ${DEPLOYDIR}/bootfiles/config.txt 6 | } 7 | -------------------------------------------------------------------------------- /recipes-multimedia/bluez-alsa/files/bluealsa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: bluealsa 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 5 7 | # Default-Stop: 8 | # Short-Description: Start services BT audio sink 9 | ### END INIT INFO 10 | 11 | /usr/bin/bluealsa -p a2dp-sink & 12 | 13 | -------------------------------------------------------------------------------- /recipes-connectivity/a2dp-agent/files/a2dp-agent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: a2dp-agent 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 5 7 | # Default-Stop: 8 | # Short-Description: Pairing agent for A2DP Bluetooth service 9 | ### END INIT INFO 10 | 11 | /usr/bin/a2dp-agent & 12 | 13 | -------------------------------------------------------------------------------- /recipes-connectivity/bluez5/bluez5_5.54.bbappend: -------------------------------------------------------------------------------- 1 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" 2 | SRC_URI += "file://main.conf" 3 | 4 | PACKAGECONFIG ??= "obex-profiles \ 5 | readline \ 6 | a2dp-profiles \ 7 | avrcp-profiles \ 8 | tools \ 9 | deprecated \ 10 | " 11 | 12 | do_install_append() { 13 | install -m 0644 ${WORKDIR}/main.conf ${D}/${sysconfdir}/bluetooth/ 14 | } 15 | -------------------------------------------------------------------------------- /recipes-core/dac-config/files/autoconnect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ADDR=$(bluetoothctl paired-devices | tail -n1 | cut -f2 -d' ') 4 | 5 | if [ -z "$ADDR" ] 6 | then 7 | exit 1 8 | fi 9 | 10 | expect < ${WORKDIR}/ext4.img 15 | mkfs.ext4 ${WORKDIR}/ext4.img 16 | cat ${WORKDIR}/ext4.img >> ${SDIMG} 17 | 18 | parted -s ${SDIMG} -- unit KiB mkpart primary ext2 ${SDIMG_SIZE} -1s 19 | } 20 | 21 | -------------------------------------------------------------------------------- /recipes-core/dac-config/dac-config.bb: -------------------------------------------------------------------------------- 1 | SUMMARY = "Configurations for Bluetooth DAC" 2 | LICENSE = "MIT" 3 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" 4 | 5 | SRC_URI = "file://bt-init.sh \ 6 | file://autoconnect.sh" 7 | 8 | DEPENDS_append = " update-rc.d-native" 9 | 10 | S = "${WORKDIR}" 11 | 12 | do_install() { 13 | # hciattach looks for firmware in /etc/firmware 14 | install -d ${D}/etc 15 | ln -s -r ${D}/lib/firmware ${D}/etc/firmware 16 | 17 | install -d ${D}${sysconfdir}/init.d 18 | install -m 0755 ${WORKDIR}/bt-init.sh ${D}${sysconfdir}/init.d 19 | install -m 0755 ${WORKDIR}/autoconnect.sh ${D}${sysconfdir}/init.d 20 | 21 | update-rc.d -r ${D} bt-init.sh start 21 2 3 4 5 . 22 | update-rc.d -r ${D} autoconnect.sh start 22 2 3 4 5 . 23 | } 24 | 25 | -------------------------------------------------------------------------------- /recipes-connectivity/a2dp-agent/a2dp-agent.bb: -------------------------------------------------------------------------------- 1 | SUMMARY = "A2DP agent" 2 | LICENSE = "MIT" 3 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" 4 | 5 | DEPENDS = "glib-2.0" 6 | 7 | SRC_URI = "file://agent.c \ 8 | file://a2dp-agent.sh" 9 | 10 | S = "${WORKDIR}" 11 | 12 | INITSCRIPT_PARAMS = "start 21 2 3 4 5 ." 13 | INITSCRIPT_NAME = "a2dp-agent.sh" 14 | 15 | inherit pkgconfig update-rc.d 16 | 17 | do_compile() { 18 | ${CC} ${LDFLAGS} `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o a2dp-agent ./agent.c `pkg-config --libs glib-2.0 gio-2.0` 19 | } 20 | 21 | do_install() { 22 | install -d ${D}${bindir} 23 | install -m 0755 a2dp-agent ${D}${bindir} 24 | 25 | install -d ${D}${sysconfdir}/init.d 26 | install -m 0755 ${WORKDIR}/a2dp-agent.sh ${D}${sysconfdir}/init.d 27 | } 28 | 29 | -------------------------------------------------------------------------------- /recipes-core/initscripts/files/mountall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: mountall 4 | # Required-Start: mountvirtfs 5 | # Required-Stop: 6 | # Default-Start: S 7 | # Default-Stop: 8 | # Short-Description: Mount all filesystems. 9 | # Description: 10 | ### END INIT INFO 11 | 12 | . /etc/default/rcS 13 | 14 | # 15 | # Mount local filesystems in /etc/fstab. For some reason, people 16 | # might want to mount "proc" several times, and mount -v complains 17 | # about this. So we mount "proc" filesystems without -v. 18 | # 19 | test "$VERBOSE" != no && echo "Mounting local filesystems..." 20 | mount -at nonfs,nosmbfs,noncpfs 2>/dev/null 21 | mount /dev/mmcblk0p3 /var/lib 22 | 23 | # 24 | # We might have mounted something over /dev, see if /dev/initctl is there. 25 | # 26 | if test ! -p /dev/initctl 27 | then 28 | rm -f /dev/initctl 29 | mknod -m 600 /dev/initctl p 30 | fi 31 | kill -USR1 1 32 | 33 | # 34 | # Execute swapon command again, in case we want to swap to 35 | # a file on a now mounted filesystem. 36 | # 37 | [ -x /sbin/swapon ] && swapon -a 38 | 39 | : exit 0 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The source code is licensed under the MIT License 2 | 3 | Copyright (c) 2020 Sami Pietikäinen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /recipes-kernel/linux/files/fragment.cfg: -------------------------------------------------------------------------------- 1 | # CONFIG_KERNEL_GZIP is not set 2 | CONFIG_KERNEL_LZ4=y 3 | # CONFIG_LIB80211 is not set 4 | 5 | # 6 | # Host-side USB support is needed for USB Network Adapter support 7 | # 8 | # CONFIG_WLAN is not set 9 | # CONFIG_B43_BUSES_BCMA_AND_SSB is not set 10 | # CONFIG_B43LEGACY_DMA_AND_PIO_MODE is not set 11 | 12 | # 13 | # Enable USB support to see WiMAX USB drivers 14 | # 15 | # CONFIG_RC_CORE is not set 16 | # CONFIG_TTPCI_EEPROM is not set 17 | # CONFIG_DVB_AS102_FE is not set 18 | # CONFIG_DVB_GP8PSK_FE is not set 19 | # CONFIG_USB_SUPPORT is not set 20 | # CONFIG_USB_DWC2_DUAL_ROLE is not set 21 | # CONFIG_USB_ZERO is not set 22 | # CONFIG_USB_AUDIO is not set 23 | # CONFIG_USB_ETH is not set 24 | # CONFIG_USB_GADGETFS is not set 25 | # CONFIG_USB_MASS_STORAGE is not set 26 | # CONFIG_USB_G_SERIAL is not set 27 | # CONFIG_USB_MIDI_GADGET is not set 28 | # CONFIG_USB_G_PRINTER is not set 29 | # CONFIG_USB_CDC_COMPOSITE is not set 30 | # CONFIG_USB_G_ACM_MS is not set 31 | # CONFIG_USB_G_MULTI is not set 32 | # CONFIG_USB_G_HID is not set 33 | # CONFIG_USB_G_WEBCAM is not set 34 | # CONFIG_AUXDISPLAY is not set 35 | # CONFIG_STAGING is not set 36 | # CONFIG_DEBUG_BUGVERBOSE is not set 37 | # CONFIG_FTRACE is not set 38 | # CONFIG_BRANCH_PROFILE_NONE is not set 39 | # CONFIG_BINARY_PRINTF is not set 40 | # CONFIG_HAMRADIO is not set 41 | # CONFIG_NETWORK_FILESYSTEMS is not set 42 | -------------------------------------------------------------------------------- /recipes-multimedia/fdk-aac/fdk-aac_2.0.1.bb: -------------------------------------------------------------------------------- 1 | # This recipe is ported from http://cgit.openembedded.org/meta-openembedded/tree/meta-multimedia/recipes-multimedia/fdk-aac/fdk-aac_2.0.1.bb 2 | # because it is not currently available in the 'warrior' branch. 3 | # 4 | # Original license for the recipe: 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE 22 | # 23 | 24 | SUMMARY = "FDK-AAC audio codec" 25 | 26 | DESCRIPTION = "The Fraunhofer FDK AAC Codec Library for Android \ 27 | (\"FDK AAC Codec\") is software that implements the MPEG \ 28 | Advanced Audio Coding (\"AAC\") encoding and decoding scheme \ 29 | for digital audio." 30 | 31 | HOMEPAGE = "https://www.iis.fraunhofer.de/en/ff/amm/impl.html" 32 | 33 | LICENSE = "Fraunhofer_FDK_AAC_Codec_Library_for_Android" 34 | LICENSE_FLAGS = "commercial" 35 | LIC_FILES_CHKSUM = "file://NOTICE;md5=5985e1e12f4afa710d64ed7bfd291875" 36 | NO_GENERIC_LICENSE[Fraunhofer_FDK_AAC_Codec_Library_for_Android] = "${WORKDIR}/NOTICE" 37 | 38 | SRC_URI = "git://github.com/mstorsjo/fdk-aac.git;protocol=git;branch=master" 39 | SRCREV = "d387d3b6ed79ff9a82c60440bdd86e6e5e324bec" 40 | 41 | S = "${WORKDIR}/git" 42 | 43 | SRC_URI[md5sum] = "fef453b5d6ee28ff302c600b8cded3e7" 44 | SRC_URI[sha256sum] = "07c2a64b098eb48b2e9d729d5e778c08f7d22f28adc8da7c3f92c58da1cbbd8e" 45 | 46 | inherit autotools 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # meta-rpi-bt-dac 2 | 3 | Yocto layer to build Bluetooth DAC image for Raspberry Pi Zero W + pHAT DAC. 4 | 5 | ## Description 6 | 7 | This layer extends the meta-raspberrypi BSP layer and builds a Linux image that allows to use Raspberry Pi Zero W and DAC hat as a Bluetooth audio sink. When the device is powered on, it will automatically become discoverable by Bluetooth. Pairing can be done without a pin, and the Pi is then recognized as a Bluetooth audio device (Advanced Audio Distribution Profile, A2DP). 8 | 9 | ## Hardware 10 | 11 | [Raspberry Pi Zero W](https://www.raspberrypi.org/products/raspberry-pi-zero-w/) 12 | 13 | [pHAT DAC](https://shop.pimoroni.com/products/phat-dac) 14 | 15 | ## Pre-built images 16 | 17 | Latest pre-built image can be found from the [Releases](https://github.com/spietika/meta-rpi-bt-dac/releases) page. It can be directly flashed to a SD card. 18 | 19 | ## Dependencies 20 | 21 | This layer depends on: 22 | 23 | * URI: git://git.yoctoproject.org/poky 24 | * branch: dunfell 25 | 26 | * URI: git://git.openembedded.org/meta-openembedded 27 | * layers: meta-oe, meta-networking, meta-python 28 | * branch: dunfell 29 | 30 | * URI: git://git.yoctoproject.org/meta-raspberrypi 31 | * branch: dunfell 32 | 33 | ## Quick Start 34 | 35 | 1. Clone the dependencies and switch to correct branch 36 | 2. source poky/oe-init-build-env build 37 | 3. Add this layer to build/conf/bblayers.conf and the dependencies above 38 | 4. Set MACHINE in local.conf to raspberrypi0-wifi 39 | * To remove unnecessary features, the following can also be added to local.conf: 40 | * `MACHINE_FEATURES_remove = "apm wifi screen touchscreen"` 41 | * `DISTRO_FEATURES_remove = "ipv4 ipv6 irda usbgadget usbhost wifi nfs zeroconf 3g nfc x11 wayland vulkan"` 42 | * For read-only root filesystem, add `IMAGE_FEATURES += "read-only-rootfs"` to local.conf. When using read-only rootfs also `SERIAL_CONSOLES_CHECK = ""` needs to be set to local.conf. 43 | 5. Add `IMAGE_FSTYPES_append = " rpi-sdimg"` to local.conf to produce ready-to-flash SD image 44 | 6. bitbake core-image-base 45 | 7. dd to a SD card the generated sdimg file (build/tmp/deploy/images/raspberrypi0-wifi/core-image-base-raspberrypi0-wifi.rpi-sdimg) 46 | 8. Boot your RPI. 47 | 48 | ## License 49 | 50 | The source is released under the MIT license. See LICENSE for details. The binary releases contain third-party components in binary form. See the accompanied licenses archive for individual licenses. 51 | -------------------------------------------------------------------------------- /recipes-multimedia/bluez-alsa/bluez-alsa_3.0.0.bb: -------------------------------------------------------------------------------- 1 | # bluez-alsa recipe based on the recipe in wiki: https://github.com/Arkq/bluez-alsa/wiki/Yocto-OE-recipe 2 | # - dropped libortp dependency 3 | # - updated to latest release tag 4 | # - no systemd dependency 5 | # 6 | # Original license for recipe: 7 | # The MIT License 8 | # 9 | # Copyright (c) 2016-2020 Arkadiusz Bokowy 10 | # 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documentation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE 28 | # 29 | 30 | SUMMARY = "Bluetooth Audio ALSA Backend" 31 | HOMEPAGE = "https://github.com/Arkq/bluez-alsa" 32 | SECTION = "devel" 33 | 34 | LICENSE = "MIT" 35 | LIC_FILES_CHKSUM = "file://LICENSE;md5=72d868d66bdd5bf51fe67734431de057" 36 | 37 | DEPENDS = "alsa-lib bluez5 glib-2.0 sbc fdk-aac" 38 | 39 | SRC_URI = "git://github.com/Arkq/bluez-alsa.git;branch=master;protocol=https;tag=v${PV} \ 40 | file://bluealsa.sh" 41 | 42 | S = "${WORKDIR}/git" 43 | 44 | INITSCRIPT_PARAMS = "start 21 2 3 4 5 ." 45 | INITSCRIPT_NAME = "bluealsa.sh" 46 | 47 | EXTRA_OECONF +="--enable-aac" 48 | 49 | inherit pkgconfig autotools update-rc.d 50 | 51 | do_install () { 52 | autotools_do_install 53 | install -d ${D}${sysconfdir}/init.d 54 | install -m 0755 ${WORKDIR}/bluealsa.sh ${D}${sysconfdir}/init.d 55 | } 56 | 57 | FILES_${PN} += "${libdir}/alsa-lib/lib*.so ${datadir}/alsa" 58 | FILES_${PN}-dev += "${libdir}/alsa-lib/*.la" 59 | FILES_${PN}-staticdev += "${libdir}/alsa-lib/lib*.a" 60 | FILES_${PN}-dbg += "${libdir}/alsa-lib/.debug/*.so" 61 | 62 | -------------------------------------------------------------------------------- /recipes-connectivity/a2dp-agent/files/agent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | GMainLoop *loop; 6 | GDBusConnection *con; 7 | #define AGENT_PATH "/org/bluez/a2dp" 8 | 9 | static void bluez_agent_method_call(GDBusConnection *conn, 10 | const gchar *sender, 11 | const gchar *path, 12 | const gchar *interface, 13 | const gchar *method, 14 | GVariant *params, 15 | GDBusMethodInvocation *invocation, 16 | void *userdata) 17 | { 18 | 19 | char *opath; 20 | char *uuid; 21 | GVariant *p= g_dbus_method_invocation_get_parameters(invocation); 22 | 23 | g_print("Agent method call: %s.%s()\n", interface, method); 24 | 25 | if(!strcmp(method, "AuthorizeService")) { 26 | g_variant_get(params, "(os)", &opath, &uuid); 27 | g_print("UUID=%s\n", uuid); 28 | 29 | if(!strcmp(uuid, "0000110d-0000-1000-8000-00805f9b34fb")) { 30 | g_print("Accepting service\n"); 31 | g_dbus_method_invocation_return_value(invocation, NULL); 32 | } 33 | else { 34 | g_print("Rejecting service\n"); 35 | g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Not supported"); 36 | } 37 | } 38 | } 39 | 40 | static const GDBusInterfaceVTable agent_method_table = { 41 | .method_call = bluez_agent_method_call, 42 | }; 43 | 44 | int bluez_register_agent(GDBusConnection *con) 45 | { 46 | GError *error = NULL; 47 | guint id = 0; 48 | GDBusNodeInfo *info = NULL; 49 | 50 | static const gchar bluez_agent_introspection_xml[] = 51 | "" 52 | " " 53 | " " 54 | " " 55 | " " 56 | " " 57 | " " 58 | ""; 59 | 60 | info = g_dbus_node_info_new_for_xml(bluez_agent_introspection_xml, &error); 61 | if(error) { 62 | g_printerr("Unable to create node: %s\n", error->message); 63 | g_clear_error(&error); 64 | return 0; 65 | } 66 | 67 | id = g_dbus_connection_register_object(con, 68 | AGENT_PATH, 69 | info->interfaces[0], 70 | &agent_method_table, 71 | NULL, NULL, &error); 72 | g_dbus_node_info_unref(info); 73 | 74 | return id; 75 | } 76 | 77 | static int bluez_agent_call_method(const gchar *method, GVariant *param) 78 | { 79 | GVariant *result; 80 | GError *error = NULL; 81 | 82 | result = g_dbus_connection_call_sync(con, 83 | "org.bluez", 84 | "/org/bluez", 85 | "org.bluez.AgentManager1", 86 | method, 87 | param, 88 | NULL, 89 | G_DBUS_CALL_FLAGS_NONE, 90 | -1, 91 | NULL, 92 | &error); 93 | if(error != NULL) { 94 | g_print("Register %s: %s\n", AGENT_PATH, error->message); 95 | return 1; 96 | } 97 | 98 | g_variant_unref(result); 99 | return 0; 100 | } 101 | 102 | static int bluez_register_autopair_agent(void) 103 | { 104 | int rc; 105 | 106 | rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, "NoInputNoOutput")); 107 | if(rc) 108 | return 1; 109 | 110 | rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH)); 111 | if(rc) { 112 | bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH)); 113 | return 1; 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | 120 | static void cleanup_handler(int signo) 121 | { 122 | if (signo == SIGINT) { 123 | g_print("received SIGINT\n"); 124 | g_main_loop_quit(loop); 125 | } 126 | } 127 | 128 | int main() 129 | { 130 | int id; 131 | int rc; 132 | 133 | if(signal(SIGINT, cleanup_handler) == SIG_ERR) 134 | g_print("can't catch SIGINT\n"); 135 | 136 | con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); 137 | if(con == NULL) { 138 | g_print("Not able to get connection to system bus\n"); 139 | return 1; 140 | } 141 | 142 | loop = g_main_loop_new(NULL, FALSE); 143 | 144 | id = bluez_register_agent(con); 145 | if(id == 0) 146 | goto fail; 147 | 148 | rc = bluez_register_autopair_agent(); 149 | if(rc) { 150 | g_print("Not able to register default autopair agent\n"); 151 | goto fail; 152 | } 153 | 154 | g_main_loop_run(loop); 155 | 156 | fail: 157 | g_dbus_connection_unregister_object(con, id); 158 | g_object_unref(con); 159 | return 0; 160 | } 161 | --------------------------------------------------------------------------------