Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bc6fea3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2010-2011 Nest, Inc.
+# All rights reserved.
+#
+# This document is the property of Nest. It is considered
+# confidential and proprietary information.
+#
+# This document may not be reproduced or transmitted in any form,
+# in whole or in part, without the express written permission of
+# Nest.
+#
+# Description:
+# This file is the makefile for BlueZ, the official Linux
+# Bluetooth protocol stack.
+#
+
+
+include pre.mak
+
+PackageName := bluez
+
+PackageSourceDir := repo
+
+PackageBuildMakefile = $(call GenerateBuildPaths,Makefile)
+
+CleanPaths += $(PackageLicenseFile)
+
+SOURCEDIRS = $(PackageSourceDir)
+$(PackageSourceDir)_RULE_TARGET = $(BuildDirectory)/configure
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/LICENSE: $(BuildDirectory)/source
+
+$(PackageLicenseFile): $(PackageSourceDir)/LICENSE
+ $(copy-result)
+
+# Prepare the sources.
+
+.PHONY: source
+source: $(BuildDirectory)/source
+$(BuildDirectory)/source: | $(PackageSourceDir) $(BuildDirectory)
+ $(Verbose)$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+ $(Verbose)touch $@
+
+# Generate the package's build makefile
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: $(BuildDirectory)/configure
+$(BuildDirectory)/configure: $(BuildDirectory)/source | $(PackageSourceDir) $(BuildDirectory)
+ $(Verbose)cd $(BuildDirectory) && ./bootstrap
+ $(Verbose)cd $(BuildDirectory) && ./configure \
+ CC="$(CC) $(CPPOPTFLAGS)" CXX="$(CXX) $(CPPOPTFLAGS)" AR=$(AR) NM=$(NM) RANLIB=$(RANLIB) STRIP=$(STRIP) INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+ CPPFLAGS="$(call ToolGenerateDefineArgument,FIRMWARE_DIR=\\\"/lib/firmware/\\\") \
+ $(call ToolGenerateIncludeArgument,$(LinuxIncludePath))" \
+ DBUS_CFLAGS="$(call ToolGenerateIncludeArgument,$(DbusIncludePaths))" \
+ GLIB_CFLAGS="$(call ToolGenerateIncludeArgument,$(GlibIncludePaths))" \
+ UDEV_CFLAGS="$(call ToolGenerateIncludeArgument,$(UdevIncludePaths))" \
+ DBUS_LIBS="$(call GenerateLibraryArgument,$(DbusLibraryPath))" \
+ GLIB_LIBS="$(call GenerateLibraryArgument,$(GlibLibraryPath))" \
+ UDEV_LIBS="$(call GenerateLibraryArgument,$(UdevLibraryPath))" \
+ PKG_CONFIG_PATH="$(GlibPkgConfigPath):$(DbusPkgConfigPath):$(UdevPkgConfigPath)" \
+ --build=$(HostTuple) \
+ --host=$(TargetTuple) \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --localstatedir=/var \
+ --disable-cups \
+ --disable-monitor \
+ --disable-client \
+ --disable-systemd \
+ --disable-obex \
+ $(if $(BUILD_FEATURE_BLUEZ_LIB), --enable-library) \
+ $(NULL)
+ $(Verbose)touch $@
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: build
+build: $(BuildDirectory)/build
+$(BuildDirectory)/build: $(BuildDirectory)/configure
+ $(Verbose)unset MAKEFLAGS && \
+ $(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+ all
+ $(Verbose)touch $@
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+$(BuildDirectory)/stage: $(BuildDirectory)/build | $(ResultDirectory)
+ $(Verbose)unset MAKEFLAGS && \
+ $(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+ DESTDIR=$(ResultDirectory) \
+ install
+ $(Verbose)touch $@
+
+stage: $(BuildDirectory)/stage
+
+clean:
+ $(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+ $(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/repo/.mailmap b/repo/.mailmap
new file mode 100644
index 0000000..a7e36e3
--- /dev/null
+++ b/repo/.mailmap
@@ -0,0 +1,11 @@
+Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com>
+Vinicius Costa Gomes <vinicius.gomes@openbossa.org> <vinicius.gomes@openbossa.org>
+Elvis Pfützenreuter <epx@signove.com> <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es> <scarot@libresoft.es>
+José Antonio Santos Cadenas <santoscadenas@gmail.com> <santoscadenas@gmail.com>
+Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> <Waldemar.Rymarkiewicz@tieto.com>
+Alok Barsode <alokbarsode@gmail.com> <alok@greatbear.(none)>
+André Dieb Martins <andre.dieb@signove.com> <andre.dieb@signove.com>
+Tedd Ho-Jeong An <tedd.an@intel.com> <tedd.an@intel.com>
+Martin Xu <martin.xu@linux.intel.com> <martin.xu@linux.intel.com>
+Marie Janssen <jamuraa@chromium.org> <jamuraa@chromium.org>
diff --git a/repo/AUTHORS b/repo/AUTHORS
new file mode 100644
index 0000000..16fb14c
--- /dev/null
+++ b/repo/AUTHORS
@@ -0,0 +1,101 @@
+Maxim Krasnyansky <maxk@qualcomm.com>
+Marcel Holtmann <marcel@holtmann.org>
+Stephen Crane <steve.crane@rococosoft.com>
+Jean Tourrilhes <jt@hpl.hp.com>
+Jan Beutel <j.beutel@ieee.org>
+Ilguiz Latypov <ilatypov@superbt.com>
+Thomas Moser <thomas.moser@tmoser.ch>
+Nils Faerber <nils@kernelconcepts.de>
+Martin Leopold <martin@leopold.dk>
+Wolfgang Heidrich <wolfgang.heidrich@esk.fhg.de>
+Fabrizio Gennari <fabrizio.gennari@philips.com>
+Brad Midgley <bmidgley@xmission.com>
+Henryk Ploetz <henryk@ploetzli.ch>
+Philip Blundell <pb@nexus.co.uk>
+Johan Hedberg <johan.hedberg@intel.com>
+Claudio Takahasi <claudio.takahasi@indt.org.br>
+Eduardo Rocha <eduardo.rocha@indt.org.br>
+Denis Kenzior <denis.kenzior@trolltech.com>
+Frederic Dalleau <frederic.dalleau@access-company.com>
+Frederic Danis <frederic.danis@access-company.com>
+Luiz Augusto von Dentz <luiz.dentz@gmail.com>
+Fabien Chevalier <fabchevalier@free.fr>
+Ohad Ben-Cohen <ohad@bencohen.org>
+Daniel Gollub <dgollub@suse.de>
+Tom Patzig <tpatzig@suse.de>
+Kai Vehmanen <kai.vehmanen@nokia.com>
+Vinicius Gomes <vinicius.gomes@openbossa.org>
+Alok Barsode <alok.barsode@azingo.com>
+Bastien Nocera <hadess@hadess.net>
+Albert Huang <albert@csail.mit.edu>
+Glenn Durfee <gdurfee@google.com>
+David Woodhouse <david.woodhouse@intel.com>
+Christian Hoene <hoene@uni-tuebingen.de>
+Pekka Pessi <pekka.pessi@nokia.com>
+Siarhei Siamashka <siarhei.siamashka@nokia.com>
+Nick Pelly <npelly@google.com>
+Lennart Poettering <lennart@poettering.net>
+Gustavo Padovan <gustavo@padovan.org>
+Marc-Andre Lureau <marc-andre.lureau@nokia.com>
+Bea Lam <bea.lam@nokia.com>
+Zygo Blaxell <zygo.blaxell@xandros.com>
+Forrest Zhao <forrest.zhao@intel.com>
+Scott Talbot <psyc@stalbot.com>
+Ilya Rubtsov <lusyaru@gmail.com>
+Mario Limonciello <mario_limonciello@dell.com>
+Filippo Giunchedi <filippo@esaurito.net>
+Jaikumar Ganesh <jaikumar@google.com>
+Elvis Pfutzenreuter <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>
+José Antonio Santos Cadenas <jcaden@libresoft.es>
+Francisco Alecrim <francisco.alecrim@openbossa.org>
+Daniel Orstadius <daniel.orstadius@gmail.com>
+Anderson Briglia <anderson.briglia@openbossa.org>
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruna Moreira <bruna.moreira@openbossa.org>
+Brian Gix <bgix@codeaurora.org>
+Andre Guedes <andre.guedes@openbossa.org>
+Sheldon Demario <sheldon.demario@openbossa.org>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Szymon Janc <szymon.janc@codecoup.pl>
+Syam Sidhardhan <s.syam@samsung.com>
+Paulo Alcantara <pcacjr@gmail.com>
+Jefferson Delfes <jefferson.delfes@openbossa.org>
+Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+Eder Ruiz Maria <eder.ruiz@openbossa.org>
+Mikel Astiz <mikel.astiz@bmw-carit.de>
+Chan-yeol Park <chanyeol.park@samsung.com>
+João Paulo Rechi Vita <jprvita@gmail.com>
+Larry Junior <larry.junior@openbossa.org>
+Raymond Liu <raymond.liu@intel.com>
+Radoslaw Jablonski <ext-jablonski.radoslaw@nokia.com>
+Rafal Michalski <michalski.raf@gmail.com>
+Dmitriy Paliy <dmitriy.paliy@nokia.com>
+Bartosz Szatkowski <bulislaw@linux.com>
+Lukasz Pawlik <lucas.pawlik@gmail.com>
+Slawomir Bochenski <lkslawek@gmail.com>
+Wayne Lee <waynelee@qualcomm.com>
+Ricky Yuen <ryuen@qualcomm.com>
+Takashi Sasai <sasai@sm.sony.co.jp>
+Andre Dieb Martins <andre.dieb@signove.com>
+Cristian Rodríguez <crrodriguez@opensuse.org>
+Alex Deymo <deymo@chromium.org>
+Petri Gynther <pgynther@google.com>
+Scott James Remnant <scott@netsplit.com>
+Jakub Tyszkowski <jakub.tyszkowski@tieto.com>
+Grzegorz Kołodziejczyk <grzegorz.kolodziejczyk@tieto.com>
+Marcin Krąglak <marcin.kraglak@tieto.com>
+Łukasz Rymanowski <lukasz.rymanowski@codecoup.pl>
+Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
+Arman Uguray <armansito@chromium.org>
+Artem Rakhov <arakhov@chromium.org>
+Mike Ryan <mikeryan@lacklustre.net>
+David Herrmann <dh.herrmann@gmail.com>
+Jacob Siverskog <jacob@teenageengineering.com>
+Sebastian Chłąd <sebastian.chlad@tieto.com>
+Alex Gal <a.gal@miip.ca>
+Loic Poulain <loic.poulain@intel.com>
+Gowtham Anandha Babu <gowtham.ab@samsung.com>
+Bharat Panda <bharat.panda@samsung.com>
+Marie Janssen <jamuraa@chromium.org>
+Jaganath Kanakkassery <jaganath.k@samsung.com>
diff --git a/repo/COPYING b/repo/COPYING
new file mode 100644
index 0000000..6d45519
--- /dev/null
+++ b/repo/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/repo/COPYING.LIB b/repo/COPYING.LIB
new file mode 100644
index 0000000..1f7c8cc
--- /dev/null
+++ b/repo/COPYING.LIB
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/repo/ChangeLog b/repo/ChangeLog
new file mode 100644
index 0000000..c7a4fc0
--- /dev/null
+++ b/repo/ChangeLog
@@ -0,0 +1,2107 @@
+ver 5.37:
+ Fix issue with registering external profiles.
+ Fix issue with connecting external profiles.
+ Fix issue with GATT service changed handling.
+ Fix issue with not emitting GattServices update.
+ Convert to unified HID over GATT profile support.
+ Convert to KeyboardDisplay as default IO capability.
+ Install btattach utility by default.
+
+ver 5.36:
+ Fix issue with PBAP headers for size query.
+ Fix issue with AVRCP current player handling.
+ Fix issue with device information handling.
+ Fix issue with device disconnect handling.
+ Fix issue with duplicate connect handling.
+ Fix issue with attribute claiming for drivers.
+
+ver 5.35:
+ Fix issue with connected devices after discovery.
+ Fix issue with profile support and LTK loading.
+ Fix issue with AVRCP events for volume control.
+ Fix issue with OBEX session owner handling.
+ Fix issue with HID over GATT setup failures.
+ Fix issue with GATT notification registration.
+ Fix issue with GATT cache validation feature.
+ Add support for persistent GATT database.
+ Add support for controller enabling option.
+
+ver 5.34:
+ Fix issue with GATT profiles and auto-connect.
+ Fix issue with missing GoepL2CapPsm SDP data.
+ Fix issue with suspending AVDTP endpoints.
+ Fix issue with audio service state on disconnect.
+ Add support for AVRCP Set Addressed Player feature.
+ Add support for AVRCP Get Folder Items feature.
+ Add support for Android 5.1 HFP WBS callbacks.
+
+ver 5.33:
+ Fix issue with memory leak in GATT database.
+ Fix issue with AVDTP set configuration handling.
+ Fix issue with AVDTP discover procedure.
+ Fix issue with not emitting Paired property.
+
+ver 5.32:
+ Fix issue with OPP GET request path handling.
+ Fix issue with ATT information request errors.
+ Fix issue with advertising instance numbers.
+ Fix issue with overwriting SDP record cache.
+ Fix issue with new connections during disconnect.
+ Add support for GATT security auto-elevation.
+
+ver 5.31:
+ Fix issue with crash in networking interface.
+ Fix issue with crash when creating endless GATT loops.
+ Fix issue with memory leak when connecting services.
+ Fix issue with memory leak creating new D-Bus proxy.
+ Fix issue with profile connections from remote devices.
+ Fix issue with GATT over BR/EDR and MTU notification.
+ Fix issue with HID and dual mode remote devices.
+ Fix issue with handling A2DP vendor codec setup.
+ Fix issue with AVRCP and syncing player state.
+ Fix issue with GATT secondary discovery handling.
+ Fix issue with wrong characteristic allocation.
+ Add support for handling BNEP setup response.
+ Add support for setting GATT database security flags.
+ Add support for setting discovery filters interface.
+ Add support for user controlled advertising interface.
+ Update Android qualification documentation to PTS 6.1 release.
+
+ver 5.30:
+ Fix compilation error in C++ due to inline function.
+ Fix issue with missing storage of device information.
+ Fix issue with GATT client and gaps in service handles.
+ Fix issue with AVDTP discovery callback crashing.
+ Fix issue with AVCTP channel handling in case of conflicts.
+ Fix issue with AVRCP target and get capabilities command.
+ Add experimental support for LE advertising manager API.
+ Add support for Android 5.1 GATT MTU exchange API.
+
+ver 5.29:
+ Fix issue with AVCTP initial key repeat timeout.
+ Fix issue with Android application disconnect handling.
+ Fix issue with Android support and service notifications.
+ Fix issue with Android support and Exchange MTU Request.
+ Fix issue with Android HFP support and AT+CMER handling.
+ Fix issue with Android HFP support and SLC setup.
+ Fix issue with Android HFP support and call hold status.
+ Fix issue with Android HFP support and indicator handling.
+ Fix issue with Android HFP support and SCO/eSCO disconnection.
+ Fix issue with Android HID over GATT support and battery service.
+ Fix issue with GATT sending Exchange MTU Request for BR/EDR.
+ Fix issue with GATT notification support without CCC.
+ Fix issue with GATT object life-time after disconnects.
+ Fix issue with GATT notification handling API.
+ Add experimental support for GATT client D-Bus API.
+ Add experimental support for GATT server D-Bus API.
+ Add support for Multi Profile Specification.
+ Update Android qualification documentation to PTS 6.0 release.
+
+ver 5.28:
+ Fix issue with GATT device discovery and probing.
+ Fix issue with bearer selection for dual-mode devices.
+ Fix issue with device removal while connected.
+ Fix issue with device name setting from inquiry response.
+ Fix issue with missing termination of name characteristic.
+ Fix issue with UTF-8 length handling for device name.
+ Fix issue with AVCTP key auto release handling.
+ Fix issue with AVCTP key press repetition handling.
+ Fix issue with payload sizes and GATT notifications.
+ Fix issue with memory corruption and GATT notifications.
+ Add support for HID proxy switching and CSR 8510 A10 devices.
+ Add support for Broadcom hex2hcd conversion utility.
+
+ver 5.27:
+ Fix issue with endian handling and management interface.
+ Fix issue with pending GATT operations when disconnecting.
+ Fix issue with 128-bit UUID conversions for HID over GATT.
+ Add support for Android 5.0 SELinux policies.
+
+ver 5.26:
+ Fix issue with handling A2DP XCASE connection state.
+ Fix issue with crash and A2DP configuration failures.
+ Fix issue with crash during OBEX session shutdown.
+ Add support for version 1.2 of Phonebook Access Profile.
+ Add support for HID over GATT get and set report handling.
+ Add support for Low Energy Secure Connections feature.
+ Add support for Bluetooth 4.2 commands and events.
+ Add support for Android 5.0 Bluetooth features.
+
+ver 5.25:
+ Fix issue with SCO connection after codec negotiation.
+ Fix issue with GATT and secondary service discovery.
+ Fix issue with GATT write descriptor callback.
+ Fix issue with MAP supported features bits.
+ Add support for MAP local time and timezone offset.
+ Add support for PBAP speed-dial and favorites folders.
+ Add support for PBAP speed-dial and identifier filters.
+ Add support for controller mode configuration option.
+ Add initial support for Android Lollipop features.
+
+ver 5.24:
+ Fix issue with storing of connection parameters.
+ Add support for Phonebook Access Profile 1.2 features.
+ Add support for Message Access Profile 1.2 event reports.
+ Add support for Android Bluetooth configuration options.
+
+ver 5.23:
+ Fix issue with concurrent authorization requests.
+ Fix issue with HID report identifier mismatch.
+ Fix issue with crash when receiving uHID events.
+ Fix issue with crash and OBEX disconnect handling.
+ Fix issue with OBEX client transfers and suspend.
+ Fix issue with parsing of MAP application parameters.
+ Fix issue with devices rejecting AVRCP GetCapabilities.
+ Add support for kernel whitelist and Android Bluetooth.
+
+ver 5.22:
+ Fix issue with UHID_OUTPUT events mapping.
+ Fix issue with UHID_FEATURE events handling.
+ Fix issue with UINT32_MAX overflow and AVRCP.
+ Fix issue when dirent type DT_UNKNOWN is returned.
+ Add support for kernel whitelist filtering feature.
+ Add support for Android Bluetooth GATT over BR/EDR.
+
+ver 5.21:
+ Fix issue with SDP requests and wrong PDU size.
+ Fix issue with handling passive scanning triggers.
+ Add support for storing and loading connection parameters.
+ Add support for kernel background auto-connection feature.
+ Add support for Android Bluetooth Scan Parameters feature.
+ Add support for Android Bluetooth Device Information feature.
+ Add support for Android Bluetooth Health Device interface.
+
+ver 5.20:
+ Fix issue with LED handling of PS3 controllers.
+ Add support for Android Bluetooth GATT server interface.
+ Add support for Android Bluetooth HID over GATT feature.
+ Add support for Android Bluetooth multi-profile feature.
+ Add support for Android Bluetooth aptX audio integration.
+
+ Note: aptX codec not included
+
+ver 5.19:
+ Fix issue with OBEX Put-Delete and Create-Empty methods.
+ Fix issue with AVRCP browsable/searchable player properties.
+ Fix issue with handling multiple default agents.
+ Fix issue with handling unpair event per bearer.
+ Fix issue with HID over GATT report ID presence.
+ Add support for HID protocol handling in userspace.
+ Add support for Bluetooth reconnection policy framework.
+ Add support for Android Bluetooth SCO over HCI transport.
+ Add support for Android Bluetooth audio quality control.
+ Add support for Android Bluetooth Low Energy only mode.
+
+ver 5.18:
+ Fix issue with identifying LE single mode devices.
+ Fix issue with L2CAP and RFCOMM peer address lookup.
+ Add support for handling OBEX authentication procedure.
+ Add support for Android Bluetooth GATT client interface.
+
+ver 5.17:
+ Fix issue with not resetting OBEX SRM setup.
+ Fix issue with BR/EDR devices and auto-connect list.
+ Fix issue with bonding complete detection as peripheral.
+ Fix issue with not updating bearer timestamp of connections.
+ Fix issue with paired property for multiple bearers.
+ Add support for Android Bluetooth Handsfree interface.
+ Add support for Android Bluetooth Wideband speech.
+
+ver 5.16:
+ Fix issue with HID over GATT physical location.
+ Fix issue with HID over GATT unique identifier.
+ Fix issue with missing paired property notification.
+ Fix issue with endianess of long term key storage.
+ Add support for storing signature resolving keys.
+ Add support for Android Bluetooth AVRCP interface.
+
+ver 5.15:
+ Fix issue with LE enabling and background scanning.
+ Fix issue with HID over GATT input device name.
+ Fix issue with storage of slave long term keys.
+ Add support for handling identity resolving keys.
+ Add support for Android Bluetooth A2DP interface.
+ Add support for Android Bluetooth audio interface.
+
+ver 5.14:
+ Fix issue with marking PS3 controllers as trusted.
+ Fix issue with authorization of PS3 controllers.
+ Add support for DualShock 4 controller detection.
+ Add support for legacy pairing emulation.
+ Add support for secure simple pairing emulation.
+ Add support for automated pairing testing.
+ Add support for RFCOMM protocol testing.
+ Add support for HCI controller testing.
+
+ver 5.13:
+ Fix issue with PS3 controller detection.
+ Add support for data transfers to L2CAP testing tool.
+ Add support for delay reporting to AVDTP testing tool.
+ Add support for Android Bluetooth Core interface.
+ Add support for Android Bluetooth Socket interface.
+ Add support for Android Bluetooth HID Host interface.
+ Add support for Android Bluetooth PAN interface.
+
+ver 5.12:
+ Fix issue with missing reply to DisconnectProfile.
+ Fix issue with icon property and class of device changes.
+ Fix issue with HID devices when SDP record is not available.
+ Fix issue with handling auto-pairing of printers.
+ Fix issue with agent authorization handling.
+ Add support for PS3 controller setup and pairing.
+ Add support for LE L2CAP CoC test capabilities.
+ Add support for AVDTP qualification test cases.
+ Add support for SMP cryptographic test cases.
+
+ver 5.11:
+ Fix issue with connection attempt when not powered.
+ Fix issue with assigning player to AVRCP target role.
+ Fix issue with OBEX default cache directory.
+ Fix issue with SDP search error handling.
+ Fix issue with processing of SDP records.
+ Fix issue with HID to HCI switching utility.
+ Fix issue with mgmt end-to-end testing tool.
+ Fix issue with L2CAP end-to-end testing tool.
+ Add support for SMP end-to-end testing tool.
+ Add support for more Wii controllers.
+
+ver 5.10:
+ Fix issue with discoverable timeout handling.
+ Fix issue with MAP messages and record version.
+ Fix issue with MAP messages and status events.
+ Fix issue with MAP messages and relative folders.
+ Fix issue with MAP messages and type property signals.
+ Fix issue with transfer size for OBEX GET operations.
+ Fix issue with AVRCP service class identifier.
+ Fix issue with AVRCP tracking seeked signal.
+ Add support for OBEX command line client.
+
+ver 5.9:
+ Fix issue with network service and adapter removal.
+ Fix issue with misleading OBEX error messages.
+ Fix issue with OBEX transport reference handling.
+ Fix issue with memory leak with MAP event handler.
+ Fix issue with missing MAP property changed signal.
+ Fix issue with message type property values.
+ Fix issue with empty UUID list for devices.
+ Fix issue with profile agent cancel method.
+ Remove dependency on USB library.
+
+ver 5.8:
+ Fix issue with missing OBEX session properties.
+ Fix issue with missing SDP service refresh.
+ Fix issue with SDP attribute range check.
+ Fix issue with priority for SDP transactions.
+ Fix issue with service discovery after pairing.
+ Fix issue with race condition in service list.
+ Fix issue with input service state transition.
+ Fix issue with default authorization for profiles.
+ Fix issue with AVRCP browsing channel connections.
+ Add support for AVRCP role agnostic sessions.
+
+ver 5.7:
+ Fix issue with missing UUID discovery during pairing.
+ Fix issue with broken patch for SDP range check handling.
+ Fix issue with AVRCP usage of UID=0 for paused/stopped.
+ Add support MAP notification dispatching.
+
+ver 5.6:
+ Fix issue with incoming connections without SDP record.
+ Fix issue with canceling ongoing device connections.
+ Fix issue with handling failed connection attempts.
+ Fix issue with pending resume during A2DP open failures.
+ Fix issue with registering AVRCP unsupported notification.
+ Fix issue with listing available AVRCP target settings.
+ Fix issue with missing error for OBEX SetPath commands.
+ Fix issue with missing OBEX session command queue.
+ Fix issue with retrieving multiple MAP event reports.
+ Add support for command line player utility.
+
+ver 5.5:
+ Fix issue with race condition between SDP and properties.
+ Fix issue with handling storage of private device addresses.
+ Fix issue with NFC out-of-band pairing and power states.
+ Fix issue with short name during device update handling.
+ Fix issue with handling AVRCP without A2DP being present.
+ Add support for handling AVRCP pass-through operations.
+ Add support for automatically reconnecting HID devices.
+ Add support for automatically pairing of devices.
+
+ver 5.4:
+ Fix issue with invalid memory access and SDP service search.
+ Add support for available player changed event for controller.
+ Add support for UIDs changed event for AVRCP controller.
+ Add support for mandatory AVRCP pass-through operations.
+ Add support for Message Notification Service (MNS) server.
+ Add support for agent methods within command line client.
+
+ver 5.3:
+ Fix issue with registering invalid profiles.
+ Fix issue with inconsistent A2DP transport state.
+ Fix issue with A2DP resume while in configured state.
+ Fix issue with buffer overflow when processing SDP response.
+ Fix issue with missing range check for SDP attribute response.
+ Fix issue with missing validation of SDP data elements.
+ Fix issue with missing fallback to static hostname.
+ Fix issue with default adapter assignment.
+
+ver 5.2:
+ Fix issue with connection handling for Low Energy.
+ Fix issue with broken device discovery handling.
+ Fix issue with invalid memory access within A2DP.
+ Fix issue with handling empty path name of SetPath.
+ Fix issue with handling Message Access Profile filters.
+ Fix issue with handling network service unregistration.
+ Fix issue with not handling bogus device pairing results.
+ Fix issue with initial service discovery and profile manager.
+ Add support for AVRCP volume notifications.
+ Add support for AVRCP browsing commands.
+
+ver 5.1:
+ Fix issue with crash when removing OBEX session.
+ Fix issue with HID device disconnected from kernel.
+ Fix issue with buffer overflow when parsing HID SDP record.
+ Fix issue with SDP_TEXT_STR16 and SDP_URL_STR16 parsing.
+ Add support for integration with systemd's hostname daemon.
+ Add support for separate adapter alias property.
+ Add support for adapter and device modalias properties.
+ Add support for official BlueZ device information.
+ Add support for asynchronous management interface handling.
+ Add tool for testing management interface compliance.
+ Add tool for testing SDP qualification requirements.
+ Add tool for testing various EIR and AD data records.
+
+ver 5.0:
+ Introduce D-Bus Properties and ObjectManager interfaces.
+ Add support for generic profile interface.
+ Add support for global agent interface.
+ Add support for integrated OBEX daemon.
+ Add support for integrated hcidump utility.
+ Add support for Bluetooth tracing and monitor utility.
+ Add support for Bluetooth command line client utility.
+ Remove support for Handsfree gateway handling.
+ Remove support for GStreamer A2DP and SBC elements.
+ Disable default installation of Bluetooth library.
+
+ver 4.101:
+ Fix issue with missing BlueZ service file.
+ Fix issue with aborting A2DP setup during AVDTP start.
+ Fix issue with handling of multiple A2DP indication.
+ Fix issue with handling AVDTP abort with invalid SEID.
+ Fix issue with rejecting AVDTP abort commands.
+ Add support for handling AVDTP command collision.
+
+ver 4.100:
+ Fix issue with crashing when SCO connection fails.
+ Fix issue with HFP gateway failing on first GSM connection.
+ Fix issue with AVRCP and handling of vendor commands.
+ Fix issue with handling AVRCP subunit info command.
+ Fix issue with missing capability for AVRCP track reached end.
+ Fix issue with AVDTP signaling and GStreamer SBC NULL check.
+ Fix issue with AVDTP Reconfigure Reject message.
+ Fix issue with incorrect EIR length parsing.
+ Fix issue with SDP disconnect for HIDSDPDisable.
+ Fix issue with SDP interoperability with Mac OS X Lion.
+ Fix issue with reverse SDP discovery with some devices.
+ Fix issue with discovering state during power off operation.
+ Add support for AVRCP Volume Changed notifications.
+ Add support for AVRCP Set Absolute Volume handling.
+ Add support for display legacy PIN code agent method.
+ Add support for multiple media transports per endpoint.
+ Add support for discovering device information characteristics.
+ Add support for vendor source for Device ID setting.
+ Add support for immediate alert server.
+ Add support for link loss server.
+
+ Notes:
+ This version requires D-Bus 1.4 or later.
+ This version requires GLib 2.28 or later.
+
+ver 4.99:
+ Fix issue with missing retries for BNEP connection setup.
+ Fix issue with not showing name if first EIR has no details.
+ Fix issue with running SDP discovery for LE devices.
+ Add support for GATT using 128-bit Bluetooth UUIDs.
+ Add support for retrieving key size information.
+ Add support for storing Long Term Keys.
+ Add support for Proximity Reporter API.
+ Add support for KeyboardDisplay IO capability.
+ Add support for version 1.0 of management API.
+ Add support for monitoring interface.
+
+ver 4.98:
+ Fix issue with adapter list upon initialization failure.
+ Fix issue with missing legacy property for Low Energy.
+ Fix issue with missing EIR information handling.
+ Fix issue with device address type tracking.
+ Fix issue with alert level characteristic.
+ Fix issue with headset shutdown handling.
+ Fix issue with Wiimote address handling.
+ Add support for advanced l2test options.
+ Add support for attribute protocol and multiple adapters.
+
+ver 4.97:
+ Update support for proximity profile.
+ Fix issue with SBC audio decoding quality.
+ Fix multiple issues with HFP support.
+ Fix multiple issues with A2DP support.
+ Fix multiple issues with AVDTP support.
+ Fix multiple issues with AVRCP support.
+ Add support for AVRCP meta-data transfer.
+ Add support for Bluetooth based thermometers.
+
+ver 4.96:
+ Fix issue with race condition in AVDTP stream start.
+ Fix issue with global adapter offline switching.
+ Fix issue with pairing and No Bonding devices.
+ Add support for Nintendo Wii Remote pairing.
+
+ver 4.95:
+ Fix issue with AVCTP replies with invalid PID.
+ Fix issue with AVRCP and unknown packet types.
+ Fix issue with AVRCP not using NOT_IMPLEMENTED correctly.
+ Fix issue with AVDTP discovery if all endpoints are in use.
+ Fix issue with invalid memory writes and media support.
+ Fix issue with not removing device alias and unbonding.
+ Fix issue with device disconnects and offline mode handling.
+ Add support for setting adapter name based on machine-info.
+ Add support for systemd service configuration.
+
+ver 4.94:
+ Fix issue with invalid read of memory in various modules.
+ Fix issue with buffer overflow when sending AVDTP commands.
+ Fix issue with response to vendor dependent AVRCP commands.
+ Fix issue with headset when not able to reply with ERROR.
+ Fix issue with crash when creating a device from storage.
+ Fix issue with handling non UTF-8 devices names.
+ Add support for improved discovery procedure.
+
+ver 4.93:
+ Fix issue with property type and Health Main channel.
+ Fix issue with crash when removing devices.
+ Add support for hid2hci and udev integration.
+
+ver 4.92:
+ Fix issue with handling of A2DP suspend response.
+ Fix issue with crashing when acquiring A2DP stream.
+ Fix issue with missing check for valid SCO before shutdown.
+ Fix issue with waiting for POLLERR when disconnecting SCO.
+ Fix issue with disconnect after primary service discovery.
+ Fix issue with attribute interface registration.
+ Add support for primary services over BR/EDR.
+ Add support for flushable packets of A2DP media.
+
+ver 4.91:
+ Fix issue with LMP version string and hciconfig.
+ Fix issue with missing discovery signal when scanning.
+ Fix issue with wrong state and canceling name resolving.
+ Fix issue with missing check during adapter initialization.
+ Fix issue with missing protocol not supported error and A2DP.
+ Fix issue with crash during driver unregistering and A2DP.
+ Fix issue with crash when receiving AVDTP close command.
+ Fix issue with remote SEP handling when A2DP codec changes.
+ Fix issue with SCO hangup handling and state changes.
+ Fix issue with security level and MCAP instances.
+ Fix issue with memory leak and HDP data channels.
+ Add support for discover characteristics by UUID to gatttool.
+ Add initial support for Out-of-Band association model.
+ Add initial support for SIM Access Profile.
+
+ver 4.90:
+ Fix issue with setting of global mode property.
+ Fix issue with handling of RequestSession responses.
+ Fix issue with TP_BNEP_CTRL_BV_01_C qualification test.
+ Fix issue with too short AVDTP request timeout.
+ Add support for SIM Access Profile manager.
+ Add support for new UUID utility functions.
+ Add support for attribute server notifications.
+ Add support for client characteristic configuration.
+ Update support for interactive GATT utility.
+
+ver 4.89:
+ Fix issue with name resolving when discovery is suspended.
+ Fix issue with parsing flags of advertising report.
+ Fix issue with SEP handling if interface is disabled.
+ Fix issue with device object creation on disconnect event.
+ Fix issue with indicators whenever the driver is initialized.
+ Fix issue with call indicator when parsing call info reply.
+ Fix issue with crash and allowed GATT MTU was too large.
+ Add support for SDP record of Primary GATT services.
+ Add support for interactive mode for GATT utility.
+
+ver 4.88:
+ Fix issue with HID channel reference count handling.
+ Fix issue with daemon exit on badly formatted AT+VTS.
+ Fix issue with crash while parsing of endpoint properties.
+ Fix issue with possible crash on AVDTP Suspend request timeout.
+ Fix issue with stopping inquiry before adapter is initialized.
+ Fix issue with creating device object when connection fails.
+ Fix issue with sending HCIDEVUP when adapter is already up.
+ Fix issue with handling bonding IO channel closing.
+ Fix agent cancellation in security mode 3 situations.
+ Update pairing code to support management interface.
+
+ver 4.87:
+ Fix issue with initialization when adapter is already up.
+ Fix issue with attribute server MTU and incoming connections.
+ Fix issue with duplicate characteristics after discovery.
+
+ver 4.86:
+ Revert wrong fix for SDP PDU size error response.
+ Fix various memory leaks in A2DP and AVDTP support.
+ Add Routing property to MediaTransport interface
+ Add proper tracking mechanism to NREC status.
+ Add READ_BLOB_REQUEST support to attribute server.
+
+ver 4.85:
+ Fix issue with event mask setting for older adapters.
+ Fix issue with device creation and pairing failures.
+ Add support for telephony support via oFono.
+ Add support for characteristic security level.
+ Update support for service registration.
+
+ver 4.84:
+ Fix issue with wrong parameters and device found signals.
+ Fix issue with leaking EIR data if RSSI does not change.
+ Fix issue with adapter initialization state.
+ Fix issue with closing of SDP server sockets.
+
+ver 4.83:
+ Fix issue with already connected HFP/HSP endpoints.
+ Fix missing reply when create device is canceled.
+ Fix memory leak within the attribute server.
+ Fix memory leak with unused extended inquiry name.
+ Fix setting paired state when device->authr is false.
+ Fix clearing authentication request for renewed keys.
+ Add support for storing link keys in runtime memory.
+ Update support for primary service discovery.
+
+ver 4.82:
+ Fix crash with mmap of files with multiples of page size.
+ Fix HFP response and hold (AT+BTRH) command response.
+ Fix device creation error response when powered off.
+ Fix device removal when connecting/browsing fails.
+ Add initial attribute permission implementation.
+ Add AVDTP SRC stream send buffer size verification.
+ Add support for setting link policy based on features.
+
+ver 4.81:
+ Fix issue with telephony driver initialization.
+ Fix issue with adapter services list initialization.
+ Fix crash after simultaneous authentication requests.
+ Add support for primary service search on device creation.
+
+ver 4.80:
+ Fix legacy link key storing for some buggy adapters.
+ Fix invalid memory access when EIR field length is zero.
+ Fix adapter initialization to wait for kernel HCI commands.
+ Fix initialization of adapters which are already up.
+ Fix possible race condition when initializing adapters.
+ Fix possible crashes when attempting to connect AVDTP.
+ Fix not aborting sink stream configuration on disconnect.
+ Fix not indicating disconnected state when connecting to AVDTP.
+ Fix not dropping AVDTP session when canceling stream setup.
+ Fix AVDTP abort not being send when the state is idle.
+ Fix regression with Low Energy and interleave discovery.
+ Add a new configuration option to disable Low Energy support.
+ Add iwmmxt optimization for SBC for ARM PXA series CPUs.
+ Update support for GATT Primary Service Discovery.
+ Update MCAP and HDP support.
+
+ver 4.79:
+ Fix issue with adapter initialization race condition.
+ Update new Bluetooth Management interface support.
+
+ver 4.78:
+ Fix various issues with AVDTP timer handling.
+ Fix various issues with handling of mode changes.
+ Fix issue with audio disconnect watch in connecting state.
+ Fix issue with handling call waiting indicators in telephony.
+ Fix issue with handling UUID parameter and RegisterEndpoint.
+ Add initial support for Bluetooth Management interface.
+ Add support for Application property to HealthChannel.
+
+ver 4.77:
+ Fix issue with device name and accessing already freed memory.
+ Fix issue with handling CHLD=0 command for handsfree.
+ Fix issue with manager properties and no adapters.
+ Fix issue with properties and broken service records.
+ Fix issue with A2DP playback and sample rate changes.
+ Update MCAP and HDP support.
+
+ver 4.76:
+ Fix issue in telephony driver with hanging up held call.
+ Fix issue in telephony driver with notifications when on hold.
+ Fix issue with blocking on setconf confirmation callback.
+ Fix issue with not always signaling new streams as sinks.
+ Fix issue with errors in case of endpoint request timeout.
+ Fix issue with HFP/HSP microphone and speaker gain values.
+ Add source if the device attempt to configure local sink stream.
+ Add PSM option for GATT/ATT over BR/EDR on gatttool.
+ Add support for GATT/ATT Attribute Write Request.
+ Update MCAP and HDP support.
+
+ver 4.75:
+ Fix use of uninitialized variable on legacy pairing.
+ Fix mismatch of attribute protocol opcode.
+
+ver 4.74:
+ Fix regression for Legacy Pairing.
+ Fix wrong PSM value for attribute protocol.
+ Fix issue with RSSI field in advertising reports.
+ Add support for Add BR/EDR and LE interleaved discovery.
+ Add support for GATT write characteristic value option.
+ Add support for specifying download address for AR300x.
+
+ver 4.73:
+ Fix problem with EIR data when setting the name.
+ Fix reading local name from command complete event.
+ Fix registering local endpoints with disabled socket interface.
+ Add support for more HCI operations using ops infrastructure.
+ Add support for GATT characteristic hierarchy.
+ Add support for GATT indications.
+
+ver 4.72:
+ Fix memory leak while connecting BTIO channels.
+ Fix crash with GStreamer plugin if SBC is not supported.
+ Fix issue with GATT server stop sending notifications.
+ Fix issue with GATT and dealing with the minimum MTU size.
+ Fix issue with file descriptor leak in GATT client.
+ Add support for UUID 128-bit handling in attribute client.
+ Add support for encoders/decoders for MTU Exchange.
+ Add support for the MTU Exchange procedure to the server.
+ Add support for a per channel MTU to the ATT server.
+ Add support for Characteristic interface.
+ Add support for new Media API and framework.
+ Add initial support for HDP plugin.
+
+ver 4.71:
+ Fix compilation when SBC support in not enabled.
+ Fix crash with RequestSession and application disconnects.
+ Fix memory leak and possible crash when removing audio device.
+ Fix issue with closing stream of locked sep when reconfiguring.
+ Fix issue where discovery could interfere with bonding.
+ Fix issue with Connected status when PS3 BD remote connects.
+ Fix issue with lifetime of fake input devices.
+ Add support for compile time option of oui.txt path.
+ Add support for printing IEEE1284 device ID for CUPS.
+ Add plugin for setting adapter class via DMI.
+ Add more features for attribute protocol and profile.
+ Add initial support for MCAP.
+
+ver 4.70:
+ Fix incoming call indication handling when in WAITING state.
+ Fix various SDP related qualification test case issues.
+ Fix logic to write EIR when SDP records are changed.
+ Fix UTF-8 validity check for remote names in EIR.
+ Add support for UUID-128 extended inquiry response.
+ Add service UUIDs from EIR to the DeviceFound signal.
+ Add fast connectable feature for Handsfree profile.
+ Add HCI command and event definitions for AMP support.
+ Add firmware download support for Qualcommh devices.
+ Add host level support for Atheros AR300x device.
+ Add initial support of ATT and GATT for basic rate.
+
+ver 4.69:
+ Fix issue with calling g_option_context_free() twice.
+ Fix inconsistencies with initial LE commands and events.
+ Add support for telephony ClearLastNumber method.
+ Add support for network server interface.
+
+ver 4.68:
+ Fix initialization of adapters in RAW mode.
+ Fix signal strength for HFP in Maemo's telephony support.
+ Add support for following the radio state via Maemo's MCE.
+ Add initial set of LE commands and events definitions.
+ Add mode option for L2CAP sockets to the BtIO API.
+
+ver 4.67:
+ Fix issue with authentication reply when bonding already completed.
+ Fix issue with not canceling authentication when bonding fails.
+ Fix issue with changed combination keys and temporary storage.
+ Fix issue with sdp_get_supp_feat library function.
+ Fix issue with missing unblock on device removal.
+ Fix issue with not waiting for mode change completion.
+ Add ARMv6 optimized version of analysis filter for SBC encoder.
+
+ver 4.66:
+ Fix regression with full debug enabling via SIGUSR2.
+ Fix redundant speaker/microphone gains being sent.
+ Fix not emitting PropertyChanged for SpeakerGain/MicrophoneGain.
+ Fix issue with storage usage when a record is not found in memory.
+ Fix issue with DiscoverServices not retrieving any records.
+ Fix audio profile disconnection order to match whitepaper.
+ Fix auto-accept confirmation when local agent has NoInputNoOutput.
+ Fix remote just-works SSP when MITM protection is required.
+ Fix performing dedicated bonding without MITM requirement.
+ Add support for storing debug link keys in runtime memory.
+
+ver 4.65:
+ Fix issues with general bonding being default setting now.
+ Fix driver removal upon device removal.
+ Add new "Blocked" property to device objects.
+ Add hciconfig support for blacklisting.
+ Add support for dynamic debug feature.
+
+ver 4.64:
+ Fix invalid memory access in headset_get_nrec function.
+ Fix issue with disconnect event on higher protocol layers.
+ Fix issue with list parsing in sdp_set_supp_features function.
+ Fix device object reference counting for SDP browse requests.
+ Add missing memory checks whenever memory is allocated for SDP.
+ Add support for exporting local services via D-Bus.
+ Add more L2CAP Enhanced Retransmission test options.
+
+ver 4.63:
+ Fix avdtp_abort not canceling pending requests.
+ Fix stale connection when abort gets rejected.
+
+ver 4.62:
+ Fix accidental symbol breakage with inquiry transmit power.
+ Fix using invalid data from previous headset connection.
+ Fix double free on AVDTP Abort response.
+ Fix possible crash while verifying AVDTP version.
+ Fix missing inuse flag when AVDTP stream is configured.
+ Add support for Bluetooth controller types.
+
+ver 4.61:
+ Fix issues with Read Inquiry Response Transmit Power Level.
+ Fix possible invalid read when removing a temporary device.
+ Fix mode restoration when remember_powered is false.
+ Fix conference call releasing in telephony-maemo.
+ Fix segmentation fault with authorization during headset disconnects.
+ Add support for handling unanswered AVDTP request on disconnect.
+ Add support for handling Inquiry Response Transmit Power Level.
+ Add support for caching of remote host features.
+ Add preliminary voice dialing support for HSP.
+
+ver 4.60:
+ Fix voice mailbox number reading from SIM.
+ Fix some races with D-Bus mainloop integration.
+ Add helpers for D-Bus signal watches.
+
+ver 4.59:
+ Add values for Bluetooth 4.0 specification.
+ Add SDP functions for HDP support.
+ Add test scripts for input and audio.
+ Fix missing close on BtIO create_io function.
+ Fix sending incorrect AVDTP commands after timeout occurs.
+ Fix timer removal when device disconnects unexpectedly.
+ Fix Extended Inquiry Response record for Device ID.
+
+ver 4.58:
+ Fix crash when adapter agent exists during authentication.
+ Fix CK-20W quirks for play and pause events.
+
+ver 4.57:
+ Fix unloading of drivers for uninitialized adapters.
+ Fix debug message to use requested and not opened SEID.
+ Fix codec selection for GStreamer plugin.
+ Fix deleting of SDP records during service updates.
+ Fix deleting of SDP records when a device is removed.
+ Fix handling when the SDP record is modified on remote device.
+ Fix potential buffer overflow by using snprintf instead of sprintf.
+ Fix const declarations for some storage function parameters.
+
+ver 4.56:
+ Add missing values from Bluetooth 3.0 specification.
+ Add proper tracking of device paired status.
+ Fix tracking of devices without permanently stored link key.
+ Fix issue with link key removal after connection failures.
+ Fix legacy pairing information based on remote host features.
+ Fix off-by-one issue with AVDTP capability parsing.
+ Fix AVRCP, AVCTP, AVDTP, A2DP and HFP version numbers.
+ Fix agent canceling before calling agent_destroy.
+ Fix service record parsing with an empty UUID list.
+ Fix various SDP related memory leaks.
+
+ver 4.55:
+ Add support for POSIX capabilities dropping.
+ Add special quirk for the Nokia CK-20W car kit.
+ Fix error code handling for AVDTP SetConfiguration response.
+ Fix updating out of range list when RSSI hasn't changed.
+ Fix various memory leaks and unnecessary error checks.
+
+ver 4.54:
+ Add introspection interface to output of introspection calls.
+ Fix stream handling when media transport disconnects prematurely.
+ Fix command timeout handling when there's no stream.
+ Fix headset_suspend_stream behavior for invalid states
+ Fix issue with AVDTP ABORTING state transition.
+ Fix issue with AVDTP suspend while closing.
+
+ver 4.53:
+ Fix issue with telephony connection state notifications.
+ Fix AVDTP stream leak for invalid media transport config.
+ Fix audio connection authorization handling with timeouts.
+ Fix race condition in authorizing audio connections.
+ Fix device authorized setting for AVRCP-only connections.
+ Fix duplicate attempts from device to connect signal channel.
+
+ver 4.52:
+ Add AVCTP support to test utility.
+ Fix AVDTP Abort when transport closes before response.
+ Fix authorization when the audio profiles are slow to connect.
+ Fix potential AVDTP reference leaks.
+
+ver 4.51:
+ Add utility for basic AVDTP testing.
+ Add support for configuring L2CAP FCS option.
+ Fix discovery mode for CUPS 1.4.x and later.
+ Fix global state tracking of audio service.
+ Fix last issues with the new build system.
+
+ver 4.50:
+ Fix issue with missing manual pages in distribution.
+ Fix issue with the configuration and state directories.
+ Fix issue with creating include directory.
+ Fix dependencies of include file generation.
+
+ver 4.49:
+ Add simple test program for basic GAP testing.
+ Add support for confirmation requests to agent example.
+ Add support for full non-recursive build.
+ Add five millisecond delay for Simple Pairing auto-accept.
+ Fix Class of Device setting when InitiallyPowered=false.
+
+ver 4.48:
+ Add library function for comparing UUID values.
+ Add support for creating all plugins as builtins.
+ Add support for async handling of service class changes.
+ Add support for source interface to audio IPC.
+ Fix device name settings when device is off or down.
+ Fix issue with enabled SCO server when not necessary.
+ Fix missing D-Bus access policy for CUPS backend.
+ Fix discovery results of CUPS backend.
+ Fix initialization handling of Maemo telephony.
+
+ver 4.47:
+ Add support for RFKILL unblock handling.
+ Add support for serial proxy configurations.
+ Add support for caching service class updates.
+ Fix issues with updating SDP service records.
+ Fix usage of limited discoverable mode.
+ Remove deprecated methods and signals for AudioSource.
+
+ver 4.46:
+ Add support for A2DP sink role.
+ Fix clearing svc_cache before the adapter is up.
+ Fix various pointer after free usages.
+ Fix various memory leaks.
+
+ver 4.45:
+ Fix UDEV_DATADIR fallback if pkg-config fails.
+ Fix adapter cleanup and setup prototypes.
+ Fix double-free with out-of-range devices.
+ Fix inband ring setting to be per-headset.
+ Fix handling of Maemo CSD startup.
+
+ver 4.44:
+ Add some missing manual pages.
+ Fix missing number prefix when installing udev rules.
+ Fix program prefix used in Bluetooth udev rules.
+ Fix three-way calling indicator order.
+ Fix downgrade/upgrade of callheld indicator.
+ Fix +CIEV sending when indicator value changes.
+ Fix signal handling for Maemo telephony driver.
+ Fix parsing issues with messages from Maemo CSD.
+ Fix issue with duplicate active calls.
+
+ver 4.43:
+ Add support for udev based on-demand startup.
+ Fix verbose error reporting of CUPS backend.
+ Fix various string length issues.
+ Fix issues with Maemo telephony driver.
+ Fix another device setup and temporary flag issue.
+ Fix and update example agent implementation.
+
+ver 4.42:
+ Add TI WL1271 to Texas Instruments chip list.
+ Add special udev mode to bluetoothd.
+ Fix regression when there is no agent registered.
+ Fix error return when bonding socket hang up.
+ Fix SCO server socket for HFP handsfree role.
+ Fix shutdown on SCO socket before closing.
+ Fix shutdown on A2DP audio stream channel before closing.
+ Fix issue with asserting on AVDTP reference count bugs.
+ Fix authorization denied issue with certain headsets.
+ Fix AVRCP UNITINFO and SUBUNIT INFO responses.
+ Fix discovery cancel issues in case SDP discovery fails.
+
+ver 4.41:
+ Fix pairing even if the ACL gets dropped before successful SDP.
+ Fix regression which caused device to be removed after pairing.
+ Fix HSP record fetching when remote device doesn't support it.
+ Fix SDP discovery canceling when clearing hs->pending.
+ Fix headset never connecting on the first attempt.
+ Fix headset state tracking if bt_search_service() fails.
+ Fix maximum headset connection count check.
+ Fix AVDTP Discover timeout handling.
+ Fix also UI_SET_KEYBIT for the new pause and play key codes.
+
+ver 4.40:
+ Add telephony driver for oFono telephony stack.
+ Add support for Dell specific HID proxy switching.
+ Add support for running hid2hci from udev.
+ Add mapping for AVRCP Play and Pause to dedicated key codes.
+ Fix AVRCP keycodes to better match existing X keymap support.
+ Fix various quoting issues within telephony support.
+ Fix memory allocation issue when generating PDUs for SDP.
+ Fix race condition on device removal.
+ Fix non-cancelable issue with CreateDevice method.
+ Fix non-working CancelDiscovery method call.
+
+ver 4.39:
+ Add workaround for dealing with unknown inquiry complete.
+ Fix discovering when using software scheduler.
+ Fix wrong NoInputNoOutput IO capability string.
+ Fix race condition with agent during pairing.
+ Fix agent cancellation for security mode 3 acceptor failure.
+ Fix temporary flag removal when device creation fails.
+ Fix hciattach to use ppoll instead of poll.
+ Fix service class update when adapter is down.
+ Fix service classes race condition during startup.
+ Fix release of audio client before freeing the device.
+
+ver 4.38:
+ Add support for builtin plugins.
+ Add framework for adapter operations.
+ Add constants for Enhanced Retransmission modes.
+ Fix HCI socket leak in device_remove_bonding.
+ Fix various format string issues.
+ Fix crashes with various free functions.
+ Fix issues with Headset and A2DP drivers to load again.
+ Fix sending AVRCP button released passthrough messages
+ Fix bug which prevent input devices to work after restart.
+ Fix issue with interpretation of UUID-128 as channel.
+
+ver 4.37:
+ Add version value for Bluetooth 3.0 devices.
+ Add additional L2CAP extended feature mask bits.
+ Add support for loading plugins in priority order.
+ Add support for more detailed usage of disconnect watches.
+ Add support for AVRCP volume control.
+ Add saturated clipping of SBC decoder output to 16-bit.
+ Fix potentially infinite recursion of adapter_up.
+ Fix SCO handling in the case of an incoming call.
+ Fix input service to use confirm callback.
+ Fix cleanup of temporary device entries from storage.
+
+ver 4.36:
+ Add proper tracking of AVCTP connect attempts.
+ Add support to channel pattern in Serial interface.
+ Fix A2DP sink crash if removing device while connecting.
+ Fix error handling if HFP indicators aren't initialized.
+ Fix segfault while handling an incoming SCO connection.
+ Fix Serial.Disconnect to abort connection attempt.
+
+ver 4.35:
+ Add support for Handsfree profile headset role.
+ Add additional checks for open SEIDs from clients.
+ Fix device removal while audio IPC client is connected.
+ Fix device removal when an authorization request is pending.
+ Fix incoming AVDTP connect while authorization in progress.
+ Fix disconnection timers for audio support.
+ Fix various potential NULL pointer deferences.
+ Fix callheld indicator value for multiple calls.
+ Fix voice number type usage.
+ Fix GDBus watch handling.
+
+ver 4.34:
+ Add support for version checks of plugins.
+ Add support for class property on adapter interface.
+ Add support for second SDP attempt after connection reset.
+ Add support for more detailed audio states.
+ Add support for HFP+A2DP auto connection feature.
+ Add support for new and improved audio IPC.
+ Add program for testing audio IPC interface.
+ Fix various AVDTP qualification related issues.
+ Fix broken SDP AttributeIdList parsing.
+ Fix invalid memory access of SDP URL handling.
+ Fix local class of device race conditions.
+ Fix issue with periodic inquiry on startup.
+ Fix missing temporary devices in some situations.
+ Fix SBC alignment issue for encoding with four subbands.
+
+ver 4.33:
+ Add Paired property to the DeviceFound signals.
+ Add support for Headset profile 1.2 version.
+ Fix broken network configuration when IPv6 is disabled.
+ Fix network regression that caused disconnection.
+ Fix SDP truncation of strings with NULL values.
+ Fix service discovery handling of CUPS helper.
+
+ver 4.32:
+ Fix broken SDP record handling.
+ Fix SDP data buffer parsing.
+ Fix more SDP memory leaks.
+ Fix read scan enable calls.
+ Fix A2DP stream handling.
+
+ver 4.31:
+ Add support for new BtIO helper library.
+ Fix AVDTP session close issue.
+ Fix SDP memory leaks.
+ Fix various uninitialized memory issues.
+ Fix duplicate signal emissions.
+ Fix property changes request handling.
+ Fix class of device storage handling.
+
+ver 4.30:
+ Add CID field to L2CAP socket address structure.
+ Fix reset of authentication requirements after bonding.
+ Fix storing of link keys when using dedicated bonding.
+ Fix storing of pre-Bluetooth 2.1 link keys.
+ Fix resetting trust settings on every reboot.
+ Fix handling of local name changes.
+ Fix memory leaks in hciconfig and hcitool
+
+ver 4.29:
+ Use AVRCP version 1.0 for now.
+ Decrease AVDTP idle timeout to one second.
+ Delay AVRCP connection when remote device connects A2DP.
+ Add workaround for AVDTP stream setup with broken headsets.
+ Add missing three-way calling feature bit for Handsfree.
+ Fix handsfree callheld indicator updating.
+ Fix parsing of all AT commands within the buffer.
+ Fix authentication replies when disconnected.
+ Fix handling of debug combination keys.
+ Fix handling of changed combination keys.
+ Fix handling of link keys when using no bonding.
+ Fix handling of invalid/unknown authentication requirements.
+ Fix closing of L2CAP raw socket used for dedicated bonding.
+
+ver 4.28:
+ Add AVDTP signal fragmentation support.
+ Add more SBC performance optimizations.
+ Add more SBC audio quality improvements.
+ Use native byte order for audio plugins.
+ Set the adapter alias only after checking the EIR data.
+ Fix auto-disconnect issue with explicit A2DP connections.
+ Fix invalid memory access of ALSA plugin.
+ Fix compilation with -Wsign-compare.
+
+ver 4.27:
+ Add more SBC optimization (MMX and ARM NEON).
+ Add BT_SECURITY and BT_DEFER_SETUP definitions.
+ Add support for deferred connection setup.
+ Add support for fragmentation of data packets.
+ Add option to trigger dedicated bonding.
+ Follow MITM requirements from remote device.
+ Require MITM for dedicated bonding if capabilities allow it.
+ Fix IO capabilities for non-pairing and pairing cases.
+ Fix no-bonding connections in non-bondable mode.
+ Fix new pairing detection with SSP.
+ Fix bonding with pre-2.1 devices and newer kernels.
+ Fix LIAC setting while toggling Pairable property.
+ Fix device creation for incoming security mode 3 connects.
+ Fix crash within A2DP with bogus pointer.
+ Fix issue with sdp_copy_record() function.
+ Fix crash with extract_des() if sdp_uuid_extract() fails.
+
+ver 4.26:
+ Use of constant shift in SBC quantization code.
+ Add possibility to analyze 4 blocks at once in encoder.
+ Fix correct handling of frame sizes in the encoder.
+ Fix for big endian problems in SBC codec.
+ Fix audio client socket to always be non-blocking.
+ Update telephony support for Maemo.
+
+ver 4.25:
+ Fix receiving data over the audio control socket.
+ Fix subbands selection for joint-stereo in SBC encoder.
+ Add new SBC analysis filter function.
+
+ver 4.24:
+ Fix signal emissions when removing adapters.
+ Fix missing adapter signals on exit.
+ Add support for bringing adapters down on exit.
+ Add support for RememberPowered option.
+ Add support for verbose compiler warnings.
+ Add more options to SBC encoder.
+
+ver 4.23:
+ Update audio IPC for better codec handling.
+ Fix bitstream optimization for SBC encoder.
+ Fix length header values of IPC messages.
+ Fix multiple coding style violations.
+ Fix FindDevice to handle temporary devices.
+ Add configuration option for DeviceID.
+ Add support for InitiallyPowered option.
+ Add missing signals for manager properties.
+ Add telephony support for Maemo.
+
+ver 4.22:
+ Add deny statements to D-Bus access policy.
+ Add support for LegacyPairing property.
+ Add support for global properties.
+ Add more commands to telephony testing script.
+ Add sender checks for serial and network interfaces.
+ Remove deprecated methods and signals from input interface.
+ Remove deprecated methods and signals from network interface.
+ Remove OffMode option and always use device down.
+
+ver 4.21:
+ Fix adapter initialization logic.
+ Fix adapter setup and start security manager early.
+ Fix usage issue with first_init variable.
+
+ver 4.20:
+ Cleanup session handling.
+ Cleanup mode setting handling.
+ Fix issue with concurrent audio clients.
+ Fix issue with HFP/HSP suspending.
+ Fix AT result code syntax handling.
+ Add Handsfree support for AT+NREC.
+ Add PairableTimeout adapter property.
+
+ver 4.19:
+ Fix installation of manual pages for old daemons.
+ Fix D-Bus signal emmissions for CreateDevice.
+ Fix issues with UUID probing.
+ Fix +BSRF syntax issue.
+ Add Pairable adapter property.
+ Add sdp_copy_record() library function.
+
+ver 4.18:
+ Fix release before close issue with RFCOMM TTYs.
+ Fix Connected property on input interface.
+ Fix DeviceFound signals during initial name resolving.
+ Fix service discovery handling.
+ Fix duplicate UUID detection.
+ Fix SBC gain mismatch and decoding handling.
+ Add more options to SBC encoder and decoder.
+ Add special any adapter object for service interface.
+ Add variable prefix to adapter and device object paths.
+
+ver 4.17:
+ Fix SBC encoder not writing last frame.
+ Fix missing timer for A2DP suspend.
+ Add more supported devices to hid2hci utility.
+ Add additional functionality to Handsfree support.
+
+ver 4.16:
+ Fix wrong parameter usage of watch callbacks.
+ Fix parameters for callback upon path removal.
+ Fix unloading of adapter drivers.
+
+ver 4.15:
+ Fix various A2DP state machine issues.
+ Fix some issues with the Handsfree error reporting.
+ Fix format string warnings with recent GCC versions.
+ Remove dependency on GModule.
+
+ver 4.14:
+ Fix types of property arrays.
+ Fix potential crash with input devices.
+ Fix PS3 BD remote input event generation.
+ Allow dynamic adapter driver registration.
+ Update udev rules.
+
+ver 4.13:
+ Fix service discovery and UUID handling.
+ Fix bonding issues with Simple Pairing.
+ Fix file descriptor misuse of SCO connections.
+ Fix various memory leaks in the device handling.
+ Fix AVCTP disconnect handling.
+ Fix GStreamer modes for MP3 encoding.
+ Add operator selection to Handsfree support.
+
+ver 4.12:
+ Fix crash with missing icon value.
+ Fix error checks of HAL plugin.
+ Fix SCO server socket cleanup on exit.
+ Fix memory leaks from DBusPendingCall.
+ Fix handling of pending authorization requests.
+ Fix missing protocol UUIDs in record pattern.
+
+ver 4.11:
+ Change SCO server socket into a generic one.
+ Add test script for dummy telephony plugin.
+ Fix uninitialized reply of multiple GetProperties methods.
+
+ver 4.10:
+ Fix memory leaks with HAL messages.
+ Add more advanced handsfree features.
+ Add properties to audio, input and network interfaces.
+ Stop device discovery timer on device removal.
+
+ver 4.9:
+ Fix signals for Powered and Discoverable properties.
+ Fix handling of Alias and Icon properties.
+ Fix duplicate entries for service UUIDs.
+
+ver 4.8:
+ Fix retrieving of formfactor value.
+ Fix retrieving of local and remote extended features.
+ Fix potential NULL pointer dereference during pairing.
+ Fix crash with browsing due to a remotely initated pairing.
+
+ver 4.7:
+ Fix pairing and service discovery logic.
+ Fix crashes during suspend and resume.
+ Fix race condition within devdown mode.
+ Add RequestSession and ReleaseSession methods.
+ Add Powered and Discoverable properties.
+ Add Devices property and deprecate ListDevices.
+ Add workaround for a broken carkit from Nokia.
+
+ver 4.6:
+ Fix Device ID record handling.
+ Fix service browsing and storage.
+ Fix authentication and encryption for input devices.
+ Fix adapter name initialization.
+
+ver 4.5:
+ Fix initialization issue with new adapters.
+ Send HID authentication request without blocking.
+ Hide the verbose SDP debug behind SDP_DEBUG.
+ Add extra UUIDs for service discovery.
+ Add SCO server socket listener.
+ Add authorization support to service plugin.
+
+ver 4.4:
+ Add temporary fix for the CUPS compile issue.
+ Add service-api.txt to distribution.
+ Mention the variable prefix of an object path
+
+ver 4.3:
+ Add dummy driver for telephony support.
+ Add support for discovery sessions.
+ Add service plugin for external services.
+ Various cleanups.
+
+ver 4.2:
+ Avoid memory copies in A2DP write routine.
+ Fix broken logic with Simple Pairing check and old kernels.
+ Allow non-bondable and outgoing SDP without agent.
+ Only remove the bonding for non-temporary devices.
+ Cleanup various unnecessary includes.
+ Make more unexported functions static.
+ Add basic infrastructure for gtk-doc support.
+
+ver 4.1:
+ Add 30 seconds timeout to BNEP connection setup phase.
+ Avoid memory copies in A2DP write routine for ALSA.
+ Make sure to include compat/sdp.h in the distribution.
+
+ver 4.0:
+ Initial public release.
+
+ver 3.36:
+ Add init routines for TI BRF chips.
+ Add extra attributes to the serial port record.
+ Add example record for headset audio gateway record.
+ Use Handsfree version 0x0105 for the gateway role.
+ Fix SDP record registration with specific record handles.
+ Fix BCSP sent/receive handling.
+ Fix various includes for cross-compilation.
+ Allow link mode settings for outgoing connections.
+ Allow bonding during periodic inquiry.
+
+ver 3.35:
+ Add two additional company identifiers.
+ Add UUID-128 support for service discovery.
+ Fix usage of friendly names for service discovery.
+ Fix authorization when experiemental is disabled.
+ Fix uninitialized variable in passkey request handling.
+ Enable output of timestamps for l2test and rctest.
+
+ver 3.34:
+ Replace various SDP functions with safe versions.
+ Add additional length validation for incoming SDP packets.
+ Use safe function versions for SDP client handling.
+ Fix issue with RemoveDevice during discovery procedure.
+ Fix collect for non-persistent service records.
+
+ver 3.33:
+ Add functions for reading and writing the link policy settings.
+ Add definition for authentication requirements.
+ Add support for handling Simple Pairing.
+ Add Simple Pairing support to Agent interface.
+ Add ReleaseMode method to Adapter interface.
+ Add DiscoverServices method to Device interface.
+ Remove obsolete code and cleanup the repository.
+ Move over to use the libgdbus API.
+ Enable PIE by default if supported.
+
+ver 3.32:
+ Add OCF constants for synchronous flow control enabling.
+ Add support for switching HID proxy devices from Dell.
+ Add more Bluetooth client/server helper functions.
+ Add support for input service idle timeout option.
+ Fix BNEP reconnection handling.
+ Fix return value for snd_pcm_hw_params() calls.
+ Use upper-case addresses for object paths.
+ Remove HAL support helpers.
+ Remove inotify support.
+ Remove service daemon activation handling.
+ Remove uneeded D-Bus API extension.
+
+ver 3.31:
+ Create device object for all pairing cases.
+ Convert authorization to internal function calls.
+ Add initial support for Headset Audio Gateway role.
+ Add generic Bluetooth helper functions for GLib.
+ Fix endiannes handling of connection handles.
+ Don't optimize when debug is enabled.
+
+ver 3.30:
+ Convert audio service into a plugin.
+ Convert input service into a plugin.
+ Convert serial service into a plugin.
+ Convert network service into a plugin.
+ Emit old device signals when a property is changed.
+ Fix missing DiscoverDevices and CancelDiscovery methods.
+ Add another company identifier.
+ Add basic support for Bluetooth sessions.
+ Add avinfo utility for AVDTP/A2DP classification.
+ Remove build option for deprecated sdpd binary.
+
+ver 3.29:
+ Introduce new D-Bus based API.
+ Add more SBC optimizations.
+ Add support for PS3 remote devices.
+ Fix alignment trap in SDP server.
+ Fix memory leak in sdp_get_uuidseq_attr function.
+
+ver 3.28:
+ Add support for MCAP UUIDs.
+ Add support for role switch for audio service.
+ Add disconnect timer for audio service.
+ Add disconnect detection to ALSA plugin.
+ Add more SBC optimizations.
+ Fix alignment issue of SDP server.
+ Remove support for SDP parsing via expat.
+
+ver 3.27:
+ Update uinput.h with extra key definitions.
+ Add support for input connect/disconnect callbacks.
+ Add ifdefs around some baud rate definitions.
+ Add another company identifier.
+ Add proper HFP service level connection handling.
+ Add basic headset automatic disconnect support.
+ Add support for new SBC API.
+ Fix SBC decoder noise at high bitpools.
+ Use 32-bit multipliers for further SBC optimization.
+ Check for RFCOMM connection state in SCO connect callback.
+ Make use of parameters selected in ALSA plugin.
+
+ver 3.26:
+ Fix compilation issues with UCHAR_MAX, USHRT_MAX and UINT_MAX.
+ Improve handling of different audio transports.
+ Enable services by default and keep old daemons disabled.
+
+ver 3.25:
+ Add limited support for Handsfree profile.
+ Add limited support for MPEG12/MP3 codec.
+ Add basic support for UNITINFO and SUBUNITINFO.
+ Add more SBC optimizations.
+ Fix external service (un)registration.
+ Allow GetInfo and GetAddress to fail.
+
+ver 3.24:
+ Add definitions for MDP.
+ Add TCP connection support for serial proxy.
+ Add fix for Logitech HID proxy switching.
+ Add missing macros, MIN, MAX, ABS and CLAMP.
+ Add more SBC encoder optimizations.
+ Add initial mechanism to handle headset commands.
+ Fix connecting to handsfree profile headsets.
+ Use proper function for checking signal name.
+
+ver 3.23:
+ Fix remote name request handling bug.
+ Fix key search function to honor the mmap area size.
+ Fix Avahi integration of network service.
+ Add new plugin communication for audio service.
+ Enable basic AVRCP support by default.
+ More optimizations to the SBC library.
+ Create common error definitions.
+
+ver 3.22:
+ Add missing include file from audio service.
+ Add SBC conformance test utility.
+ Add basic uinput support for AVRCP.
+ Fix L2CAP socket leak in audio service.
+ Fix buffer usage in GStreamer plugin.
+ Fix remote name request event handling.
+
+ver 3.21:
+ Add constant for Bluetooth socket options level.
+ Add initial AVRCP support.
+ Add A2DP sink support to GStreamer plugin.
+ Fix interoperability with A2DP suspend.
+ Fix sign error in 8-subband encoder.
+ Fix handling of service classes length size.
+ Store Extended Inquiry Response data information.
+ Publish device id information through EIR.
+ Support higher baud rates for Ericcson based chips.
+
+ver 3.20:
+ Fix GStreamer plugin file type detection.
+ Fix potential infinite loop in inotify support.
+ Fix D-Bus signatures for dict handling.
+ Fix issues with service activation.
+ Fix SDP failure handling of audio service.
+ Fix various memory leaks in input service.
+ Add secure device creation method to input service.
+ Add service information methods to serial service.
+ Add config file support to network service.
+ Add scripting capability to network service.
+ Add special on-mode handling.
+ Add optimization for SBC encoder.
+ Add tweaks for D-Bus 1.1.x libraries.
+ Add support for inquiry transmit power level.
+
+ver 3.19:
+ Limit range of bitpool announced while in ACP side.
+ Use poll instead of usleep to wait for worker thread.
+ Use default event mask from the specification.
+ Add L2CAP mode constants.
+ Add HID proxy support for Logitech diNovo Edge dongle.
+ Add refresh option to re-request device names.
+ Show correct connection link type.
+
+ver 3.18:
+ Don't allocate memory for the Bluetooth base UUID.
+ Implement proper locking for headsets.
+ Fix various A2DP SEP locking issues.
+ Fix and cleanup audio stream handling.
+ Fix stream starting if suspend request is pending.
+ Fix A2DP and AVDTP endianess problems.
+ Add network timeout and retransmission support.
+ Add more detailed decoding of EIR elements.
+
+ver 3.17:
+ Fix supported commands bit calculation.
+ Fix crashes in audio and network services.
+ Check PAN source and destination roles.
+ Only export the needed symbols for the plugins.
+
+ver 3.16:
+ Update company identifier list.
+ Add support for headsets with SCO audio over HCI.
+ Add support for auto-create through ALSA plugin.
+ Add support for ALSA plugin parameters.
+ Add GStreamer plugin with SBC decoder and encoder.
+ Fix network service NAP, GN and PANU servers.
+ Set EIR information from SDP database.
+
+ver 3.15:
+ Add A2DP support to the audio service.
+ Add proxy support to the serial service.
+ Extract main service class for later use.
+ Set service classes value from SDP database.
+
+ver 3.14:
+ Add missing signals for the adapter interface.
+ Add definitions and functions for Simple Pairing.
+ Add basic commands for Simple Pairing.
+ Add correct Simple Pairing and EIR interaction.
+ Add missing properties for remote information.
+ Add EPoX endian quirk to the input service.
+ Fix HID descriptor import and storage functions.
+ Fix handling of adapters in raw mode.
+ Fix remote device listing methods.
+
+ver 3.13:
+ Fix some issues with the headset support.
+ Fix concurrent pending connection attempts.
+ Fix usage of devname instead of netdev.
+ Add identifier for Nokia SyncML records.
+ Add command for reading the CSR chip revision.
+ Add generic CSR radio test support.
+ Update HCI command table.
+
+ver 3.12:
+ Add missing HCI command text descriptions
+ Add missing HCI commands structures.
+ Add missing HCI event structures.
+ Add common bachk() function.
+ Add support for limited discovery mode.
+ Add support for setting of event mask.
+ Add GetRemoteServiceIdentifiers method.
+ Add skeleton for local D-Bus server.
+ Add headset gain control methods.
+ Fix various headset implementation issues.
+ Fix various serial port service issues.
+ Fix various input service issues.
+ Let CUPS plugin discover printers in range.
+ Improve the BCM2035 UART init routine.
+ Ignore connection events for non-ACL links.
+
+ver 3.11:
+ Update API documentation.
+ Minimize SDP root records and browse groups.
+ Use same decoder for text and URL strings.
+ Fix URL data size handling.
+ Fix SDP pattern extraction for XML.
+ Fix network connection persistent state.
+ Add network connection helper methods.
+ Add initial version of serial port support.
+ Add class of device tracking.
+
+ver 3.10.1:
+ Add option to disable installation of manual pages.
+ Fix input service encryption setup.
+ Fix serial service methods.
+ Fix network service connection handling.
+ Provide a simple init script.
+
+ver 3.10:
+ Add initial version of network service.
+ Add initial version of serial service.
+ Add initial version of input service.
+ Add initial version of audio service.
+ Add authorization framework.
+ Add integer based SBC library.
+ Add version code for Bluetooth 2.1 specification.
+ Add ESCO_LINK connection type constant.
+ Export sdp_uuid32_to_uuid128() function.
+
+ver 3.9:
+ Add RemoteDeviceDisconnectRequested signal.
+ Add updated service framework.
+ Add embedded GLib library.
+ Add support for using system GLib library.
+ Create internal SDP server library.
+
+ver 3.8:
+ Sort discovered devices list based on their RSSI.
+ Send DiscoverableTimeoutChanged signal.
+ Fix local and remote name validity checking.
+ Add ListRemoteDevices and ListRecentRemoteDevices methods.
+ Add basic integration of confirmation concept.
+ Add support for service record description via XML.
+ Add support for external commands to the RFCOMM utility.
+ Add experimental service and authorization API.
+ Add functions for registering binary records.
+
+ver 3.7:
+ Fix class of device handling.
+ Fix error replies with pairing and security mode 3.
+ Fix disconnect method for RFCOMM connections.
+ Add match pattern for service searches.
+ Add support for prioritized watches.
+ Add additional PDU length checks.
+ Fix CSRC value for partial responses.
+
+ver 3.6.1:
+ Fix IO channel race conditions.
+ Fix pairing issues on big endian systems.
+ Fix pairing issues with page timeout errors.
+ Fix pairing state for security mode 3 requests.
+ Switch to user as default security manager mode.
+
+ver 3.6:
+ Update D-Bus based RFCOMM interface support.
+ Use L2CAP raw sockets for HCI connection creation.
+ Add periodic discovery support to the D-Bus interface.
+ Add initial support for device names via EIR.
+ Add proper UTF-8 validation of device names.
+ Add support for the J-Three keyboard.
+ Fix issues with the asynchronous API for SDP.
+
+ver 3.5:
+ Fix and cleanup watch functionality.
+ Add support for periodic inquiry mode.
+ Add support for asynchronous SDP requests.
+ Add more request owner tracking.
+ Add asynchronous API for SDP.
+ Document pageto and discovto options.
+
+ver 3.4:
+ Improve error reporting for failed HCI commands.
+ Improve handling of CancelBonding.
+ Fixed bonding reply message when disconnected.
+ Fix UUID128 string lookup handling.
+ Fix malloc() versus bt_malloc() usage.
+
+ver 3.3:
+ Don't change inquiry mode for Bluetooth 1.1 adapters.
+ Add udev rules for Bluetooth serial PCMCIA cards.
+ Add Cancel and Release methods for passkey agents.
+ Add GetRemoteClass method.
+ Convert to using ppoll() and pselect().
+ Initialize allocated memory to zero.
+ Remove bcm203x firmware loader.
+ Remove kernel specific timeouts.
+ Add additional private data field for SDP sessions.
+ Add host controller to host flow control defines.
+ Add host number of completed packets defines.
+ Initialize various memory to zero before usage.
+
+ver 3.2:
+ Only check for the low-level D-Bus library.
+ Update possible device minor classes.
+ Fix timeout for pending reply.
+ Add more Inquiry with RSSI quirks.
+ Sleep only 100 msecs for device detection.
+ Don't send BondingCreated on link key renewal.
+ Allow storing of all UTF-8 remote device names.
+ Create storage filenames with a generic function.
+ Fix handling of SDP strings.
+ Add adapter type for SDIO cards.
+ Add features bit for link supervision timeout.
+
+ver 3.1:
+ Add missing placeholders for feature bits.
+ Fix handling of raw mode devices.
+ Fix busy loop in UUID extraction routine.
+ Remove inquiry mode setting.
+ Remove auth and encrypt settings.
+
+ver 3.0:
+ Implement the new BlueZ D-Bus API.
+ Fix broken behavior with EVT_CMD_STATUS.
+ Add features bit for pause encryption.
+ Add additional EIR error code.
+ Add more company identifiers.
+ Add another Phonebook Access identifier.
+ Update sniff subrating data structures.
+
+ver 2.25:
+ Use %jx instead of %llx for uint64_t and int64_t.
+ Allow null-terminated text strings.
+ Add UUID for N-Gage games.
+ Add UUID for Apple Macintosh Attributes.
+ Add Apple attributes and iSync records.
+ Add definitions for Apple Agent.
+ Add support for the Handsfree Audio Gateway service.
+ Add support for choosing a specific record handle.
+ Add support for dialup/telephone connections.
+ Add definitions for Apple Agent.
+ Add support for record handle on service registration.
+
+ver 2.24:
+ Fix display of SDP text and data strings.
+ Add support for device scan property.
+ Add support for additional access protocols.
+ Update the D-Bus policy configuration file.
+
+ver 2.23:
+ Update the new D-Bus interface.
+ Make dfutool ready for big endian architectures.
+ Add support for AVRCP specific service records.
+ Add support for writing complex BCCMD commands.
+ Add the new BCCMD interface utility.
+ Add MicroBCSP implementation from CSR.
+ Add constants and definitions for sniff subrating.
+ Add support for allocation of binary text elements.
+ Add HCI emulation tool.
+ Add fake HID support for old EPoX presenters.
+ Reject connections from unknown HID devices.
+ Fix service discovery deadlocks with Samsung D600 phones.
+
+ver 2.22:
+ Remove D-Bus 0.23 support.
+ Add initial version of the new D-Bus interface.
+ Add support for extended inquiry response commands.
+ Add support for the Logitech diNovo Media Desktop Laser.
+ Add compile time buffer checks (FORTIFY SOURCE).
+ Decode reserved LMP feature bits.
+ Fix errno overwrite problems.
+ Fix profile descriptor problem with Samsung phones.
+
+ver 2.21:
+ Move create_dirs() and create_file() into the textfile library.
+ Let textfile_put() also replace the last key value pair.
+ Fix memory leaks with textfile_get() usage.
+ Fix infinite loops and false positive matches.
+ Don't retrieve stored link keys for RAW devices.
+ Document the putkey and delkey commands.
+ Show supported commands also in clear text.
+ Support volatile changes of the BD_ADDR for CSR chips.
+ Add support for identification of supported commands.
+ Add missing OCF declarations for the security filter.
+ Add two new company identifiers.
+
+ver 2.20:
+ Add UUIDs for video distribution profile.
+ Add UUIDs for phonebook access profile.
+ Add attribute identifier for supported repositories.
+ Add definitions for extended inquiry response.
+ Add functions for extended inquiry response.
+ Add support for extended inquiry response.
+ Add support for HotSync service record.
+ Add support for ActiveSync service record.
+ Add ActiveSync networking support.
+ Fix D-Bus crashes with new API versions.
+
+ver 2.19:
+ Fix the GCC 4.0 warnings.
+ Fix the routing for dealing with raw devices.
+ Fix off by one memory allocation error.
+ Fix security problem with escape characters in device name.
+ Add per device service record functions.
+ Send D-Bus signals for inquiry results and remote name resolves.
+ Add support for device specific SDP records.
+
+ver 2.18:
+ Support D-Bus 0.23 and 0.33 API versions.
+ Support reading of complex BCCMD values.
+ Support minimum and maximum encryption key length.
+ Add support for reading and writing the inquiry scan type.
+ Add definitions for connection accept timeout and scan enable.
+ Add support for inquiry scan type.
+ Add tool for the CSR BCCMD interface.
+ Add first draft of the Audio/Video control utility.
+ Add disconnect timer support for the A2DP ALSA plugin.
+ Make SBC parameters configurable.
+ Replace non-printable characters in device names.
+ Remove hci_vhci.h header file.
+ Remove hci_uart.h header file.
+
+ver 2.17:
+ Set the storage directory through ${localstatedir}.
+ Add the textfile library for ASCII based file access.
+ Add support for return link keys event.
+ Add support for voice setting configuration.
+ Add support for page scan timeout configuration.
+ Add support for storing and deleting of stored link keys.
+ Add support for searching for services with UUID-128.
+ Add support for retrieving all possible service records.
+ Add support for a raw mode view of service records.
+ Add support for HID information caching in hidd.
+ Add support for authentication in pand and dund.
+ Add support for changing BD_ADDR of CSR chips.
+ Add pskey utility for changing CSR persistent storage values.
+ Add the firmware upgrade utility.
+ Add connection caching for the A2DP ALSA plugin.
+ Add functions for stored link keys.
+ Add definitions for PIN type and unit key.
+ Add SDP_WAIT_ON_CLOSE flag for sdp_connect().
+ Include stdio.h in bluetooth.h header file.
+ Include sys/socket.h in the header files.
+
+ver 2.16:
+ Store link keys in ASCII based file format.
+ Support device name caching.
+ Support zero length data sizes in l2test.
+ Change default l2ping data size to 44 bytes.
+ Hide the server record and the public browse group root.
+ Read BD_ADDR if not set and if it is a raw device.
+ Add SDP language attributes.
+ Add support for browsing the L2CAP group.
+ Add support for stored pin codes for outgoing connections.
+ Add support for local commands and extended features.
+ Add support for reading CSR panic and fault codes.
+ Add config option for setting the inquiry mode.
+ Add OUI decoding support.
+ Use unlimited inquiry responses as default.
+ Use cached device names for PIN request.
+ Use the clock offset when getting the remote names.
+ Add function for reading local supported commands.
+ Add function for reading local extended features.
+ Add function for reading remote extended features.
+ Add function for getting the remote name with a clock offset.
+ Add function for extracting the OUI from a BD_ADDR.
+ Add inquiry info structure with RSSI and page scan mode.
+ Fix buffer allocation for features to string conversion.
+ Support inquiry with unlimited number of responses.
+
+ver 2.15:
+ Enable the RFCOMM service level security.
+ Add deprecated functions for reading the name.
+ Add command for reading the clock offset.
+ Add command for reading the clock.
+ Add function for reading the clock.
+ Add function for reading the local Bluetooth address.
+ Add function for reading the local supported features.
+ Don't configure raw devices.
+ Don't set inquiry scan or page scan on raw devices.
+ Don't show extended information for raw devices.
+ Support L2CAP signal sizes bigger than 2048 bytes.
+ Cleanup of the socket handling code of the test programs.
+ Use better way for unaligned access.
+ Remove sdp_internal.h and its usage.
+
+ver 2.14:
+ Make use of additional connection information.
+ Use library function for reading the RSSI.
+ Use library function for reading the link quality.
+ Use library function for reading the transmit power level.
+ Use library functions for the link supervision timeout.
+ Add tool for changing the device address.
+ Add function for reading the RSSI.
+ Add function for reading the link quality.
+ Add function for reading the transmit power level.
+ Add functions for the link supervision timeout.
+ Remove deprecated functions.
+ Update AM_PATH_BLUEZ macro.
+
+ver 2.13:
+ Use file permission 0600 for the link key file.
+ Add support for HID attribute descriptions.
+ Add support for Device ID attributes.
+ Add Device ID and HID attribute definitions.
+ Update the UUID constants and its translations.
+ Update L2CAP socket option definitions.
+ Update connection information definitions.
+ Various whitespace cleanups.
+
+ver 2.12:
+ Inherit the device specific options from the default.
+ Use --device for selecting the source device.
+ Add --nosdp option for devices with resource limitation.
+ Add support and parameter option for secure mode.
+ Add a lot of build ids and hardware revisions.
+ Add service classes and profile ids for WAP.
+ Add simple AM_PATH_BLUEZ macro.
+ Update UUID translation tables.
+ Correct kernel interface for CMTP and HIDP support.
+
+ver 2.11:
+ Initial support for the kernel security manager.
+ Various cleanups to avoid inclusion of kernel headers.
+ Fix output when the CUPS backend is called without arguments.
+ Fix problems with a 64 bit userland.
+ Use Bluetooth library functions if available.
+ Use standard numbering scheme of SDP record handles.
+ Use bit zero for vendor packets in the filter type bitmask.
+ Add SIM Access types for service discovery.
+ Add more audio/video profile translations.
+ Add another company identifier.
+ Add the missing HCI error codes.
+ Add RFCOMM socket options.
+ Add definition for the SECURE link mode.
+ Add functions for reading and writing the inquiry mode.
+ Add functions for AFH related settings and information.
+ Add version identifier for the Bluetooth 2.0 specification.
+ Add a master option to the hidd.
+ Add support for changing the link key of a connection.
+ Add support for requesting encryption on keyboards.
+ Add support for revision information of Digianswer devices.
+ Add support for the Zoom, IBM and TDK PCMCIA cards.
+ Add checks for the OpenOBEX and the ALSA libraries.
+ Add experimental mRouter support.
+
+ver 2.10:
+ Use a define for the configuration directory.
+ Fix string initialization for flags translation.
+ Fix and extend the unaligned access macros.
+ Make compiling with debug information optional.
+ Don't override CFLAGS from configure.
+ Check for usb_get_busses() and usb_interrupt_read().
+ Add optional support for compiling with PIE.
+ Make installation of the init scripts optional.
+ Make compiling with debug information optional.
+ Don't override CFLAGS from configure.
+
+ver 2.9:
+ Retry SDP connect if busy in the CUPS backend.
+ Use packet type and allow role switch in hcitool.
+ Use the functions from the USB library for hid2hci.
+ Add Broadcom firmware loader.
+ Add EPoX endian quirk for buggy keyboards.
+ Add L2CAP info type and info result definitions.
+ Add value for L2CAP_CONF_RFC_MODE.
+ Change RSSI value to signed instead of unsigned.
+ Allow UUID32 values as protocol identifiers.
+ Update the autoconf/automake scripts.
+
+ver 2.8:
+ Use LIBS and LDADD instead of LDFLAGS.
+ Use HIDP subclass field for HID boot protocol.
+ Set olen before calling getsockopt() in pand.
+ Restore signals for dev-up script.
+ Add PID file support for pand.
+ Add size parameter to expand_name() in hcid.
+ Add support for audio source and audio sink SDP records.
+ Add support for HID virtual cable unplug.
+ Add support for AmbiCom BT2000C card.
+ Add defines and UUID's for audio/video profiles.
+ Add AVDTP protocol identifier.
+ Add HIDP subclass field.
+ Add PKGConfig support.
+ Fix the event code of inquiry with RSSI.
+ Remove dummy SDP library.
+
+ver 2.7:
+ Fix display of decoded LMP features.
+ Update company identifiers.
+ Add AFH related types.
+ Add first bits from EDR prototyping specification.
+ Add support for inquiry with RSSI.
+ Add HCRP related SDP functions.
+ Add HIDP header file.
+ Add support for getting the AFH channel map.
+ Add support for AFH mode.
+ Add support for inquiry mode.
+ Add Bluetooth backend for CUPS.
+ Add the hid2hci utility.
+ Add the hidd utility.
+ Add the pand utility.
+ Add the dund utility.
+ More endian bug fixes.
+ Give udev some time to create the RFCOMM device nodes.
+ Release the TTY if no device node is found.
+ New startup script for the Bluetooth subsystem.
+ Update to the autoconf stuff.
+
+ver 2.6:
+ Change default prefix to /usr.
+ Add manpages for hcid and hcid.conf.
+ Add the sdpd server daemon.
+ Add the sdptool utility.
+ Add the ciptool utility.
+ Add new company identifiers.
+ Add BNEP and CMTP header files.
+ Add the SDP library.
+ Use R2 for default value of pscan_rep_mode.
+
+ver 2.5:
+ Add decoding of Bluetooth 1.2 features.
+ Add link manager version parameter for Bluetooth 1.2.
+ Add new company identifiers.
+ Add D-Bus support for PIN request.
+ Support for transmit power level.
+ Support for park, sniff and hold mode.
+ Support for role switch.
+ Support for reading the clock offset.
+ Support for requesting authentication.
+ Support for setting connection encryption.
+ Show revision information for Broadcom devices.
+ Replace unprintable characters in device name.
+ Use R1 for default value of pscan_rep_mode.
+ Fix some 64-bit problems.
+ Fix some endian problems.
+ Report an error on PIN helper failure.
+ Update bluepin script for GTK2.
+
+ver 2.4:
+ Increase number of inquiry responses.
+ Support for transmit power level.
+ Display all 8 bytes of the features.
+ Add support for reading and writing of IAC.
+ Correct decoding class of device.
+ Use Ericsson revision command for ST Microelectronics devices.
+ Display AVM firmware version with 'revision' command.
+ New code for CSR specific revision information.
+ Support for ST Microelectronics specific initialization.
+ Support for 3Com card version 3.0.
+ Support for TDK, IBM and Socket cards.
+ Support for initial baud rate.
+ Update man pages.
+ Fixes for some memory leaks.
+
+ver 2.3:
+ Added const qualifiers to appropriate function arguments.
+ Minor fixes.
+ CSR firmware version is now displayed by 'revision' command.
+ Voice command is working properly on big endian machines.
+ Added support for Texas Bluetooth modules.
+ Added support for high UART baud rates on Ericsson modules.
+ BCSP initialization fixes.
+ Support for role switch command (hcitool).
+ RFCOMM config file parser fixes.
+ Update man pages.
+ Removed GLib dependency.
+
+ver 2.2:
+ Updated RFCOMM header file.
+ Additional HCI command and event defines.
+ Support for voice settings (hciconfig).
+ Minor hcitool fixes.
+ Improved configure script.
+ Added Headset testing tool.
+ Updated man pages.
+ RPM package.
+
+ver 2.1.1:
+ Resurrect hci_remote_name.
+
+ver 2.1:
+ Added hci_{read, write}_class_of_dev().
+ Added hci_{read, write}_current_iac_lap().
+ Added hci_write_local_name().
+ Added RFCOMM header file.
+ Minor fixes.
+ Improved BCSP initialization (hciattach).
+ Support for displaying link quality (hcitool).
+ Support for changing link supervision timeout (hcitool).
+ New RFCOMM TTY configuration tool (rfcomm).
+ Minor fixes and updates.
+
+ver 2.0:
+ Additional company IDs.
+ BCSP initialization (hciattach).
+ Minor hciconfig fixes.
+
+ver 2.0-pr13:
+ Support for multiple pairing modes.
+ Link key database handling fixes.
+
+ver 2.0-pre12:
+ Removed max link key limit. Keys never expire.
+ Link key database is always updated. Reread PIN on SIGHUP (hcid).
+ Bluetooth script starts SDPd, if installed.
+ Other minor fixes.
+
+ver 2.0-pre11:
+ Improved link key management and more verbose logging (hcid).
+ Fixed scan command (hcitool).
+
+ver 2.0-pre10:
+ Fix hci_inquiry function to return errors and accept user buffers.
+ New functions hci_devba, hci_devid, hci_for_each_dev and hci_get_route.
+ Additional company IDs.
+ Makefile and other minor fixes.
+ Support for reading RSSI, remote name and changing
+ connection type (hcitool).
+ Device initialization fixes (hcid).
+ Other minor fixes and improvements.
+ Build environment cleanup and fixes.
+
+ver 2.0-pre9:
+ Improved bluepin. Working X authentication.
+ Improved hcitool. New flexible cmd syntax, additional commands.
+ Human readable display of the device features.
+ LMP features to string translation support.
+ Additional HCI command and event defines.
+ Extended hci_filter API.
+
+ver 2.0-pre8:
+ Additional HCI ioctls and defines.
+ All strings and buffers are allocated dynamically.
+ ba2str, str2ba automatically swap bdaddress.
+ Additional hciconfig commands. Support for ACL and SCO MTU ioctls.
+ Support for Inventel and COM1 UART based devices.
+ Minor hcitool fixes.
+ Improved l2test. New L2CAP test modes.
+ Minor fixes and cleanup.
+
+ver 2.0-pre7:
+ Bluetooth libraries and header files is now a separate package.
+ New build environment uses automake and libtool.
+ Massive header files cleanup.
+ Bluetooth utilities is now a separate package.
+ New build environment uses automake.
+ Moved all config files and security data to /etc/bluetooth.
+ Various cleanups.
+
+ver 2.0-pre6:
+ API cleanup and additions.
+ Improved hcitool.
+ l2test minor output fixes.
+ hciattach opt to display list of supported devices.
+
+ver 2.0-pre4:
+ HCI filter enhancements.
+
+ver 2.0-pre3:
+ Cleanup.
+
+ver 2.0-pre2:
+ Additional HCI library functions.
+ Improved CSR baud rate initialization.
+ PCMCIA scripts fixes and enhancements.
+ Documentation update.
+
+ver 2.0-pre1:
+ New UART initialization utility.
+ Hot plugging support for UART based PCMCIA devices.
+ SCO testing utility.
+ New authentication utility (bluepin).
+ Minor fixes and improvements.
diff --git a/repo/HACKING b/repo/HACKING
new file mode 100644
index 0000000..a8fb403
--- /dev/null
+++ b/repo/HACKING
@@ -0,0 +1,130 @@
+Hacking on BlueZ
+****************
+
+Build tools requirements
+========================
+
+When building and testing directly from the repository it is important to
+have at least automake version 1.10 or later installed. All modern
+distributions should default to the latest version, but it seems that
+Debian's default is still an earlier version:
+
+ Check version
+ # dpkg -l '*automake*'
+
+ Install new version
+ # apt-get install automake1.10
+ # update-alternatives --config automake
+
+
+Working with the source code repository
+=======================================
+
+The repository contains two extra scripts that accomplish the bootstrap
+process. One is called "bootstrap" which is the basic scripts that uses the
+autotools scripts to create the needed files for building and installing.
+It makes sure to call the right programs depending on the usage of shared or
+static libraries or translations etc.
+
+The second program is called "bootstrap-configure". This program will make
+sure to properly clean the repository, call the "bootstrap" script and then
+call configure with proper settings for development. It will use the best
+options and pass them over to configure. These options normally include
+the enabling the maintainer mode and the debugging features.
+
+So while in a normal source project the call "./configure ..." is used to
+configure the project with its settings like prefix and extra options. In
+case of bare repositories call "./bootstrap-configure" and it will bootstrap
+the repository and calls configure with all the correct options to make
+development easier.
+
+In case of preparing for a release with "make distcheck", don't use
+bootstrap-configure since it could export development specific settings.
+
+So the normal steps to checkout, build and install such a repository is
+like this:
+
+ Checkout repository
+ # git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git
+ # cd bluez
+
+ Configure and build
+ # ./bootstrap-configure
+ # make
+
+ Configure and build with cgcc (Sparse)
+ # ./bootstrap-configure CC=cgcc
+ # make
+
+ Run unit tests
+ # make check
+
+ Check installation
+ # make install DESTDIR=$PWD/x
+ # find x
+ # rm -rf x
+
+ Check distribution
+ # make distcheck
+
+ Final installation
+ # sudo make install
+
+ Remove autogenerated files
+ # make maintainer-clean
+
+
+Running from within the source code repository
+==============================================
+
+When using "./configure --enable-maintainer-mode" the automake scripts will
+use the plugins directly from within the repository. This removes the need
+to use "make install" when testing "bluetoothd". The "bootstrap-configure"
+automatically includes this option.
+
+ Copy configuration file which specifies the required security policies
+ # sudo cp ./src/bluetooth.conf /etc/dbus-1/system.d/
+
+ Run daemon in foreground with debugging
+ # sudo ./src/bluetoothd -n -d
+
+ Run daemon with valgrind
+ # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes \
+ --show-possibly-lost=no --leak-check=full --suppressions=./tools/valgrind.supp \
+ ./src/bluetoothd -n -d
+
+For production installations or distribution packaging it is important that
+the "--enable-maintainer-mode" option is NOT used.
+
+Note multiple arguments to -d can be specified, colon, comma or space
+separated. The arguments are relative source code filenames for which
+debugging output should be enabled; output shell-style globs are
+accepted (e.g.: 'plugins/*:src/main.c').
+
+Submitting patches
+==================
+
+If you fixed a bug or you want to add support for something, patches are
+welcome! In order to ease the inclusion of your patch, it's important to follow
+some rules, otherwise it will likely be rejected by maintainers.
+
+BlueZ rules for submitting patches follow most of the rules used by Linux kernel
+(https://www.kernel.org/doc/Documentation/SubmittingPatches) with some remarks:
+
+1) Do *not* add "Signed-off-by" lines in your commit messages. BlueZ does not
+use them, so including them is actually an error.
+
+2) Be sure to follow the coding style rules of BlueZ. They are listed in
+doc/coding-style.txt.
+
+3) Split your patch according to the top-level directories. E.g.: if you added
+a feature that touches files under 'include/', 'src/' and 'drivers/'
+directories, split in three separated patches, taking care not to
+break compilation.
+
+4) Bug fixes should be sent first as they take priority over new features.
+
+5) The commit message should follow 50/72 formatting which means the header
+should be limited to 50 characters and the description should be wrapped at 72
+characters except if it contains quoted information from debug tools like
+backtraces, compiler errors, etc.
diff --git a/repo/INSTALL b/repo/INSTALL
new file mode 100644
index 0000000..56b077d
--- /dev/null
+++ b/repo/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script). Here is a another example:
+
+ /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/repo/Makefile.am b/repo/Makefile.am
new file mode 100644
index 0000000..3e1d8d0
--- /dev/null
+++ b/repo/Makefile.am
@@ -0,0 +1,505 @@
+
+AM_MAKEFLAGS = --no-print-directory
+
+lib_LTLIBRARIES =
+
+noinst_LIBRARIES =
+
+noinst_LTLIBRARIES =
+
+bin_PROGRAMS =
+
+noinst_PROGRAMS =
+
+dist_man_MANS =
+
+dist_noinst_MANS =
+
+CLEANFILES =
+
+EXTRA_DIST =
+
+libexecdir = @libexecdir@/bluetooth
+
+libexec_PROGRAMS =
+
+includedir = @includedir@/bluetooth
+
+include_HEADERS =
+
+AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS)
+AM_LDFLAGS = $(MISC_LDFLAGS)
+
+if DATAFILES
+dbusdir = @DBUS_CONFDIR@/dbus-1/system.d
+dbus_DATA = src/bluetooth.conf
+
+confdir = $(sysconfdir)/bluetooth
+conf_DATA =
+
+statedir = $(localstatedir)/lib/bluetooth
+state_DATA =
+endif
+
+if SYSTEMD
+systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
+systemdsystemunit_DATA = src/bluetooth.service
+
+dbussystembusdir = @DBUS_SYSTEMBUSDIR@
+dbussystembus_DATA = src/org.bluez.service
+endif
+
+EXTRA_DIST += src/bluetooth.service.in src/org.bluez.service
+
+plugindir = $(libdir)/bluetooth/plugins
+
+if MAINTAINER_MODE
+build_plugindir = $(abs_top_srcdir)/plugins/.libs
+else
+build_plugindir = $(plugindir)
+endif
+
+
+plugin_LTLIBRARIES =
+
+lib_sources = lib/bluetooth.c lib/hci.c lib/sdp.c
+lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+ lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+ lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+
+extra_headers = lib/mgmt.h lib/uuid.h lib/a2mp.h lib/amp.h
+extra_sources = lib/uuid.c
+
+local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
+
+BUILT_SOURCES = $(local_headers) src/builtin.h
+
+if LIBRARY
+include_HEADERS += $(lib_headers)
+
+lib_LTLIBRARIES += lib/libbluetooth.la
+
+lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:10:18
+lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+endif
+
+noinst_LTLIBRARIES += lib/libbluetooth-internal.la
+
+lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \
+ $(extra_headers) $(extra_sources)
+
+noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
+
+gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \
+ gdbus/mainloop.c gdbus/watch.c \
+ gdbus/object.c gdbus/client.c gdbus/polkit.c
+
+noinst_LTLIBRARIES += src/libshared-glib.la src/libshared-mainloop.la
+
+shared_sources = src/shared/io.h src/shared/timeout.h \
+ src/shared/queue.h src/shared/queue.c \
+ src/shared/util.h src/shared/util.c \
+ src/shared/mgmt.h src/shared/mgmt.c \
+ src/shared/crypto.h src/shared/crypto.c \
+ src/shared/ecc.h src/shared/ecc.c \
+ src/shared/ringbuf.h src/shared/ringbuf.c \
+ src/shared/tester.h src/shared/tester.c \
+ src/shared/hci.h src/shared/hci.c \
+ src/shared/hci-crypto.h src/shared/hci-crypto.c \
+ src/shared/hfp.h src/shared/hfp.c \
+ src/shared/uhid.h src/shared/uhid.c \
+ src/shared/pcap.h src/shared/pcap.c \
+ src/shared/btsnoop.h src/shared/btsnoop.c \
+ src/shared/ad.h src/shared/ad.c \
+ src/shared/att-types.h \
+ src/shared/att.h src/shared/att.c \
+ src/shared/gatt-helpers.h src/shared/gatt-helpers.c \
+ src/shared/gatt-client.h src/shared/gatt-client.c \
+ src/shared/gatt-server.h src/shared/gatt-server.c \
+ src/shared/gatt-db.h src/shared/gatt-db.c \
+ src/shared/gap.h src/shared/gap.c
+
+src_libshared_glib_la_SOURCES = $(shared_sources) \
+ src/shared/io-glib.c \
+ src/shared/timeout-glib.c
+
+src_libshared_mainloop_la_SOURCES = $(shared_sources) \
+ src/shared/io-mainloop.c \
+ src/shared/timeout-mainloop.c \
+ src/shared/mainloop.h src/shared/mainloop.c
+
+attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
+ attrib/gatt.h attrib/gatt.c \
+ attrib/gattrib.h attrib/gattrib.c \
+ attrib/gatt-service.h attrib/gatt-service.c
+
+btio_sources = btio/btio.h btio/btio.c
+
+gobex_sources = gobex/gobex.h gobex/gobex.c \
+ gobex/gobex-defs.h gobex/gobex-defs.c \
+ gobex/gobex-packet.c gobex/gobex-packet.h \
+ gobex/gobex-header.c gobex/gobex-header.h \
+ gobex/gobex-transfer.c gobex/gobex-debug.h \
+ gobex/gobex-apparam.c gobex/gobex-apparam.h
+
+builtin_modules =
+builtin_sources =
+builtin_nodist =
+
+include Makefile.plugins
+
+if MAINTAINER_MODE
+plugin_LTLIBRARIES += plugins/external-dummy.la
+plugins_external_dummy_la_SOURCES = plugins/external-dummy.c
+plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+ -no-undefined
+plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
+endif
+
+libexec_PROGRAMS += src/bluetoothd
+
+src_bluetoothd_SOURCES = $(builtin_sources) \
+ $(attrib_sources) $(btio_sources) \
+ src/bluetooth.ver \
+ src/main.c src/log.h src/log.c \
+ src/backtrace.h src/backtrace.c \
+ src/systemd.h src/systemd.c \
+ src/rfkill.c src/hcid.h src/sdpd.h \
+ src/sdpd-server.c src/sdpd-request.c \
+ src/sdpd-service.c src/sdpd-database.c \
+ src/attrib-server.h src/attrib-server.c \
+ src/gatt-database.h src/gatt-database.c \
+ src/sdp-xml.h src/sdp-xml.c \
+ src/sdp-client.h src/sdp-client.c \
+ src/textfile.h src/textfile.c \
+ src/uuid-helper.h src/uuid-helper.c \
+ src/uinput.h \
+ src/plugin.h src/plugin.c \
+ src/storage.h src/storage.c \
+ src/advertising.h src/advertising.c \
+ src/agent.h src/agent.c \
+ src/error.h src/error.c \
+ src/adapter.h src/adapter.c \
+ src/profile.h src/profile.c \
+ src/service.h src/service.c \
+ src/gatt-client.h src/gatt-client.c \
+ src/device.h src/device.c src/attio.h \
+ src/dbus-common.c src/dbus-common.h \
+ src/eir.h src/eir.c
+src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
+ gdbus/libgdbus-internal.la \
+ src/libshared-glib.la \
+ @BACKTRACE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
+ -Wl,--version-script=$(srcdir)/src/bluetooth.ver
+
+src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
+ gdbus/libgdbus-internal.la \
+ src/libshared-glib.la \
+ src/bluetooth.service
+
+src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
+ -DPLUGINDIR=\""$(build_plugindir)"\"
+src_bluetoothd_SHORTNAME = bluetoothd
+
+builtin_files = src/builtin.h $(builtin_nodist)
+
+nodist_src_bluetoothd_SOURCES = $(builtin_files)
+
+CLEANFILES += $(builtin_files) src/bluetooth.service
+
+man_MANS = src/bluetoothd.8
+
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+ src/main.conf profiles/network/network.conf \
+ profiles/input/input.conf profiles/proximity/proximity.conf
+
+test_scripts =
+unit_tests =
+
+include Makefile.tools
+include Makefile.obexd
+include android/Makefile.am
+
+if HID2HCI
+rulesdir = @UDEV_DIR@/rules.d
+
+rules_DATA = tools/97-hid2hci.rules
+
+CLEANFILES += $(rules_DATA)
+endif
+
+EXTRA_DIST += tools/hid2hci.rules
+
+if TEST
+testdir = $(pkglibdir)/test
+test_SCRIPTS = $(test_scripts)
+endif
+
+EXTRA_DIST += $(test_scripts)
+
+EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt \
+ doc/test-coverage.txt \
+ doc/test-runner.txt \
+ doc/settings-storage.txt
+
+EXTRA_DIST += doc/mgmt-api.txt \
+ doc/adapter-api.txt doc/device-api.txt \
+ doc/agent-api.txt doc/profile-api.txt \
+ doc/network-api.txt doc/media-api.txt \
+ doc/health-api.txt doc/sap-api.txt \
+ doc/input-api.txt
+
+EXTRA_DIST += doc/alert-api.txt \
+ doc/proximity-api.txt doc/heartrate-api.txt \
+ doc/thermometer-api.txt doc/cyclingspeed-api.txt \
+ doc/gatt-api.txt doc/advertising-api.txt
+
+EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
+
+EXTRA_DIST += doc/pics-opp.txt doc/pixit-opp.txt \
+ doc/pts-opp.txt
+
+EXTRA_DIST += tools/magic.btsnoop
+
+AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@ @UDEV_CFLAGS@
+
+AM_CPPFLAGS = -I$(builddir)/lib
+
+
+unit_tests += unit/test-eir
+
+unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/uuid-helper.c
+unit_test_eir_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+ @GLIB_LIBS@
+
+unit_tests += unit/test-uuid
+
+unit_test_uuid_SOURCES = unit/test-uuid.c
+unit_test_uuid_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \
+ @GLIB_LIBS@
+
+unit_tests += unit/test-textfile
+
+unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c
+unit_test_textfile_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-crc
+
+unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c
+unit_test_crc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-crypto
+
+unit_test_crypto_SOURCES = unit/test-crypto.c
+unit_test_crypto_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-ecc
+
+unit_test_ecc_SOURCES = unit/test-ecc.c
+unit_test_ecc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-ringbuf unit/test-queue
+
+unit_test_ringbuf_SOURCES = unit/test-ringbuf.c
+unit_test_ringbuf_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_test_queue_SOURCES = unit/test-queue.c
+unit_test_queue_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-mgmt
+
+unit_test_mgmt_SOURCES = unit/test-mgmt.c
+unit_test_mgmt_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-uhid
+
+unit_test_uhid_SOURCES = unit/test-uhid.c
+unit_test_uhid_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-sdp
+
+unit_test_sdp_SOURCES = unit/test-sdp.c \
+ src/sdpd.h src/sdpd-database.c \
+ src/log.h src/log.c \
+ src/sdpd-service.c src/sdpd-request.c
+unit_test_sdp_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avdtp
+
+unit_test_avdtp_SOURCES = unit/test-avdtp.c \
+ src/log.h src/log.c \
+ android/avdtp.c android/avdtp.h
+unit_test_avdtp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avctp
+
+unit_test_avctp_SOURCES = unit/test-avctp.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h
+unit_test_avctp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-avrcp
+
+unit_test_avrcp_SOURCES = unit/test-avrcp.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h \
+ android/avrcp-lib.c android/avrcp-lib.h
+unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-hfp
+
+unit_test_hfp_SOURCES = unit/test-hfp.c
+unit_test_hfp_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+unit_tests += unit/test-gdbus-client
+
+unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
+unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@ @DBUS_LIBS@
+
+unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
+ unit/test-gobex-transfer unit/test-gobex-apparam
+
+unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+ unit/test-gobex.c
+unit_test_gobex_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+ unit/test-gobex-packet.c
+unit_test_gobex_packet_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+ unit/test-gobex-header.c
+unit_test_gobex_header_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+ unit/test-gobex-transfer.c
+unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+ unit/test-gobex-apparam.c
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+
+unit_tests += unit/test-lib
+
+unit_test_lib_SOURCES = unit/test-lib.c
+unit_test_lib_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-gatt
+
+unit_test_gatt_SOURCES = unit/test-gatt.c
+unit_test_gatt_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-hog
+
+unit_test_hog_SOURCES = unit/test-hog.c \
+ $(btio_sources) \
+ profiles/input/hog-lib.h profiles/input/hog-lib.c \
+ profiles/scanparam/scpp.h profiles/scanparam/scpp.c \
+ profiles/battery/bas.h profiles/battery/bas.c \
+ profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \
+ src/log.h src/log.c \
+ attrib/att.h attrib/att.c \
+ attrib/gatt.h attrib/gatt.c \
+ attrib/gattrib.h attrib/gattrib.c
+unit_test_hog_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la @GLIB_LIBS@
+
+unit_tests += unit/test-gattrib
+
+unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c $(btio_sources) src/log.h src/log.c
+unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la \
+ @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+
+if MAINTAINER_MODE
+noinst_PROGRAMS += $(unit_tests)
+endif
+
+TESTS = $(unit_tests)
+AM_TESTS_ENVIRONMENT = MALLOC_CHECK_=3 MALLOC_PERTURB_=69
+
+if DBUS_RUN_SESSION
+AM_TESTS_ENVIRONMENT += dbus-run-session --
+endif
+
+if VALGRIND
+LOG_COMPILER = valgrind --error-exitcode=1 --num-callers=30
+LOG_FLAGS = --trace-children=yes --leak-check=full --show-reachable=no \
+ --suppressions=$(srcdir)/tools/valgrind.supp --quiet
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+if LIBRARY
+pkgconfig_DATA = lib/bluez.pc
+endif
+
+manual_pages = doc/btmon.1
+
+if MANPAGES
+dist_noinst_MANS += $(manual_pages)
+endif
+
+EXTRA_DIST += $(manual_pages:.1=.txt)
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \
+ --enable-manpages --enable-android \
+ --disable-systemd --disable-udev
+
+DISTCLEANFILES = $(pkgconfig_DATA) $(unit_tests) $(manual_pages)
+
+MAINTAINERCLEANFILES = Makefile.in \
+ aclocal.m4 configure config.h.in config.sub config.guess \
+ ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver
+
+SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
+ $(SED) -e 's,@libexecdir\@,$(libexecdir),g' \
+ < $< > $@
+
+%.service: %.service.in Makefile
+ $(SED_PROCESS)
+
+%.1: %.txt
+ $(AM_V_GEN)a2x --doctype manpage --format manpage $(srcdir)/$<
+
+src/builtin.h: src/genbuiltin $(builtin_sources)
+ $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+
+tools/%.rules:
+ $(AM_V_GEN)cp $(srcdir)/$(subst 97-,,$@) $@
+
+$(lib_libbluetooth_la_OBJECTS): $(local_headers)
+
+lib/bluetooth/%.h: lib/%.h
+ $(AM_V_at)$(MKDIR_P) lib/bluetooth
+ $(AM_V_GEN)$(LN_S) -f "$(abs_top_builddir)"/$< $@
+
+if COVERAGE
+clean-coverage:
+ @lcov --directory $(top_builddir) --zerocounters
+ $(RM) -r coverage $(top_builddir)/coverage.info
+
+coverage: check
+ @lcov --compat-libtool --directory $(top_builddir) --capture \
+ --output-file $(top_builddir)/coverage.info
+ $(AM_V_at)$(MKDIR_P) coverage
+ @genhtml -o coverage/ $(top_builddir)/coverage.info
+
+clean-local: clean-coverage
+ -find $(top_builddir) -name "*.gcno" -delete
+ -find $(top_builddir) -name "*.gcda" -delete
+ $(RM) -r lib/bluetooth
+
+else
+clean-local:
+ -find $(top_builddir) -name "*.gcno" -delete
+ -find $(top_builddir) -name "*.gcda" -delete
+ $(RM) -r lib/bluetooth
+endif
diff --git a/repo/Makefile.obexd b/repo/Makefile.obexd
new file mode 100644
index 0000000..2e33cbc
--- /dev/null
+++ b/repo/Makefile.obexd
@@ -0,0 +1,110 @@
+
+if SYSTEMD
+systemduserunitdir = @SYSTEMD_USERUNITDIR@
+systemduserunit_DATA = obexd/src/obex.service
+
+dbussessionbusdir = @DBUS_SESSIONBUSDIR@
+dbussessionbus_DATA = obexd/src/org.bluez.obex.service
+endif
+
+EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service
+
+obex_plugindir = $(libdir)/obex/plugins
+
+obexd_builtin_modules =
+obexd_builtin_sources =
+obexd_builtin_nodist =
+
+obexd_builtin_modules += filesystem
+obexd_builtin_sources += obexd/plugins/filesystem.c obexd/plugins/filesystem.h
+
+obexd_builtin_modules += bluetooth
+obexd_builtin_sources += obexd/plugins/bluetooth.c
+
+if EXPERIMENTAL
+obexd_builtin_modules += pcsuite
+obexd_builtin_sources += obexd/plugins/pcsuite.c
+endif
+
+obexd_builtin_modules += opp
+obexd_builtin_sources += obexd/plugins/opp.c
+
+obexd_builtin_modules += ftp
+obexd_builtin_sources += obexd/plugins/ftp.c obexd/plugins/ftp.h
+
+if OBEX
+obexd_builtin_modules += irmc
+obexd_builtin_sources += obexd/plugins/irmc.c
+
+obexd_builtin_modules += pbap
+obexd_builtin_sources += obexd/plugins/pbap.c \
+ obexd/plugins/vcard.h obexd/plugins/vcard.c \
+ obexd/plugins/phonebook.h \
+ obexd/plugins/phonebook-dummy.c
+endif
+
+obexd_builtin_modules += mas
+obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \
+ obexd/plugins/messages.h \
+ obexd/plugins/messages-dummy.c
+
+obexd_builtin_modules += mns
+obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
+ obexd/client/map-event.h
+
+libexec_PROGRAMS += obexd/src/obexd
+
+obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
+ $(obexd_builtin_sources) \
+ obexd/src/main.c obexd/src/obexd.h \
+ obexd/src/plugin.h obexd/src/plugin.c \
+ obexd/src/log.h obexd/src/log.c \
+ obexd/src/manager.h obexd/src/manager.c \
+ obexd/src/obex.h obexd/src/obex.c obexd/src/obex-priv.h \
+ obexd/src/mimetype.h obexd/src/mimetype.c \
+ obexd/src/service.h obexd/src/service.c \
+ obexd/src/transport.h obexd/src/transport.c \
+ obexd/src/server.h obexd/src/server.c \
+ obexd/client/manager.h obexd/client/manager.c \
+ obexd/client/session.h obexd/client/session.c \
+ obexd/client/bluetooth.h obexd/client/bluetooth.c \
+ obexd/client/sync.h obexd/client/sync.c \
+ obexd/client/pbap.h obexd/client/pbap.c \
+ obexd/client/ftp.h obexd/client/ftp.c \
+ obexd/client/opp.h obexd/client/opp.c \
+ obexd/client/map.h obexd/client/map.c \
+ obexd/client/map-event.h obexd/client/map-event.c \
+ obexd/client/transfer.h obexd/client/transfer.c \
+ obexd/client/transport.h obexd/client/transport.c \
+ obexd/client/dbus.h obexd/client/dbus.c \
+ obexd/client/driver.h obexd/client/driver.c \
+ obexd/src/map_ap.h
+obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
+ gdbus/libgdbus-internal.la \
+ @ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
+
+obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
+
+obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
+ @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \
+ -DPLUGINDIR=\""$(obex_plugindir)"\" \
+ -fPIC -D_FILE_OFFSET_BITS=64
+
+obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src
+
+obexd_src_obexd_SHORTNAME = obexd
+
+obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist)
+
+nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files)
+
+BUILT_SOURCES += obexd/src/builtin.h
+
+obexd/src/plugin.$(OBJEXT): obexd/src/builtin.h
+
+obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources)
+ $(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@
+
+CLEANFILES += obexd/src/builtin.h $(builtin_files) obexd/src/obex.service
+
+EXTRA_DIST += obexd/src/genbuiltin
diff --git a/repo/Makefile.plugins b/repo/Makefile.plugins
new file mode 100644
index 0000000..f85b642
--- /dev/null
+++ b/repo/Makefile.plugins
@@ -0,0 +1,125 @@
+
+builtin_modules += hostname
+builtin_sources += plugins/hostname.c
+
+builtin_modules += wiimote
+builtin_sources += plugins/wiimote.c
+
+builtin_modules += autopair
+builtin_sources += plugins/autopair.c
+
+builtin_modules += policy
+builtin_sources += plugins/policy.c
+
+if MAINTAINER_MODE
+builtin_modules += gatt_example
+builtin_sources += plugins/gatt-example.c
+endif
+
+if EXPERIMENTAL
+builtin_modules += neard
+builtin_sources += plugins/neard.c
+
+builtin_modules += sap
+builtin_sources += profiles/sap/main.c profiles/sap/manager.h \
+ profiles/sap/manager.c profiles/sap/server.h \
+ profiles/sap/server.c profiles/sap/sap.h \
+ profiles/sap/sap-dummy.c
+
+noinst_LIBRARIES += profiles/sap/libsap.a
+profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
+endif
+
+builtin_modules += a2dp
+builtin_sources += profiles/audio/source.h profiles/audio/source.c \
+ profiles/audio/sink.h profiles/audio/sink.c \
+ profiles/audio/a2dp.h profiles/audio/a2dp.c \
+ profiles/audio/avdtp.h profiles/audio/avdtp.c \
+ profiles/audio/media.h profiles/audio/media.c \
+ profiles/audio/transport.h profiles/audio/transport.c \
+ profiles/audio/a2dp-codecs.h
+
+builtin_modules += avrcp
+builtin_sources += profiles/audio/control.h profiles/audio/control.c \
+ profiles/audio/avctp.h profiles/audio/avctp.c \
+ profiles/audio/avrcp.h profiles/audio/avrcp.c \
+ profiles/audio/player.h profiles/audio/player.c
+
+builtin_modules += network
+builtin_sources += profiles/network/manager.c \
+ profiles/network/bnep.h profiles/network/bnep.c \
+ profiles/network/server.h profiles/network/server.c \
+ profiles/network/connection.h \
+ profiles/network/connection.c
+
+builtin_modules += input
+builtin_sources += profiles/input/manager.c \
+ profiles/input/server.h profiles/input/server.c \
+ profiles/input/device.h profiles/input/device.c \
+ profiles/input/hidp_defs.h
+
+builtin_modules += hog
+builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \
+ profiles/input/hog-lib.c profiles/input/hog-lib.h \
+ profiles/deviceinfo/dis.c profiles/deviceinfo/dis.h \
+ profiles/battery/bas.c profiles/battery/bas.h \
+ profiles/scanparam/scpp.c profiles/scanparam/scpp.h \
+ profiles/input/suspend.h profiles/input/suspend-none.c
+
+EXTRA_DIST += profiles/input/suspend-dummy.c
+
+if EXPERIMENTAL
+builtin_modules += health
+builtin_sources += profiles/health/mcap.h profiles/health/mcap.c \
+ profiles/health/hdp_main.c profiles/health/hdp_types.h \
+ profiles/health/hdp_manager.h \
+ profiles/health/hdp_manager.c \
+ profiles/health/hdp.h profiles/health/hdp.c \
+ profiles/health/hdp_util.h profiles/health/hdp_util.c
+endif
+
+builtin_modules += gap
+builtin_sources += profiles/gap/gas.c
+
+builtin_modules += scanparam
+builtin_sources += profiles/scanparam/scan.c
+
+builtin_modules += deviceinfo
+builtin_sources += profiles/deviceinfo/deviceinfo.c
+
+if EXPERIMENTAL
+builtin_modules += alert
+builtin_sources += profiles/alert/server.c
+
+builtin_modules += time
+builtin_sources += profiles/time/server.c
+
+builtin_modules += proximity
+builtin_sources += profiles/proximity/main.c profiles/proximity/manager.h \
+ profiles/proximity/manager.c \
+ profiles/proximity/monitor.h \
+ profiles/proximity/monitor.c \
+ profiles/proximity/reporter.h \
+ profiles/proximity/reporter.c \
+ profiles/proximity/linkloss.h \
+ profiles/proximity/linkloss.c \
+ profiles/proximity/immalert.h \
+ profiles/proximity/immalert.c
+
+builtin_modules += thermometer
+builtin_sources += profiles/thermometer/thermometer.c
+
+builtin_modules += heartrate
+builtin_sources += profiles/heartrate/heartrate.c
+
+builtin_modules += cyclingspeed
+builtin_sources += profiles/cyclingspeed/cyclingspeed.c
+endif
+
+if SIXAXIS
+plugin_LTLIBRARIES += plugins/sixaxis.la
+plugins_sixaxis_la_SOURCES = plugins/sixaxis.c
+plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+ -no-undefined @UDEV_LIBS@
+plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden @UDEV_CFLAGS@
+endif
diff --git a/repo/Makefile.tools b/repo/Makefile.tools
new file mode 100644
index 0000000..e79b53b
--- /dev/null
+++ b/repo/Makefile.tools
@@ -0,0 +1,421 @@
+
+if CLIENT
+bin_PROGRAMS += client/bluetoothctl
+
+client_bluetoothctl_SOURCES = client/main.c \
+ client/display.h client/display.c \
+ client/agent.h client/agent.c \
+ client/gatt.h client/gatt.c \
+ monitor/uuid.h monitor/uuid.c
+client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
+ -lreadline
+endif
+
+if MONITOR
+bin_PROGRAMS += monitor/btmon
+
+monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
+ monitor/display.h monitor/display.c \
+ monitor/hcidump.h monitor/hcidump.c \
+ monitor/ellisys.h monitor/ellisys.c \
+ monitor/control.h monitor/control.c \
+ monitor/packet.h monitor/packet.c \
+ monitor/vendor.h monitor/vendor.c \
+ monitor/lmp.h monitor/lmp.c \
+ monitor/crc.h monitor/crc.c \
+ monitor/ll.h monitor/ll.c \
+ monitor/l2cap.h monitor/l2cap.c \
+ monitor/sdp.h monitor/sdp.c \
+ monitor/avctp.h monitor/avctp.c \
+ monitor/avdtp.h monitor/avdtp.c \
+ monitor/a2dp.h monitor/a2dp.c \
+ monitor/rfcomm.h monitor/rfcomm.c \
+ monitor/bnep.h monitor/bnep.c \
+ monitor/uuid.h monitor/uuid.c \
+ monitor/hwdb.h monitor/hwdb.c \
+ monitor/keys.h monitor/keys.c \
+ monitor/analyze.h monitor/analyze.c \
+ monitor/intel.h monitor/intel.c \
+ monitor/broadcom.h monitor/broadcom.c
+monitor_btmon_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-mainloop.la @UDEV_LIBS@
+endif
+
+if EXPERIMENTAL
+noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \
+ peripheral/btsensor tools/3dsp \
+ tools/mgmt-tester tools/gap-tester \
+ tools/l2cap-tester tools/sco-tester \
+ tools/smp-tester tools/hci-tester \
+ tools/rfcomm-tester tools/bnep-tester \
+ tools/userchan-tester
+
+emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
+ emulator/serial.h emulator/serial.c \
+ emulator/server.h emulator/server.c \
+ emulator/vhci.h emulator/vhci.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c \
+ emulator/phy.h emulator/phy.c \
+ emulator/amp.h emulator/amp.c \
+ emulator/le.h emulator/le.c
+emulator_btvirt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+emulator_b1ee_SOURCES = emulator/b1ee.c
+emulator_b1ee_LDADD = src/libshared-mainloop.la
+
+emulator_hfp_SOURCES = emulator/hfp.c
+emulator_hfp_LDADD = src/libshared-mainloop.la
+
+peripheral_btsensor_SOURCES = peripheral/main.c \
+ peripheral/efivars.h peripheral/efivars.c \
+ peripheral/attach.h peripheral/attach.c \
+ peripheral/log.h peripheral/log.c \
+ peripheral/gap.h peripheral/gap.c \
+ peripheral/gatt.h peripheral/gatt.c
+peripheral_btsensor_LDADD = src/libshared-mainloop.la \
+ lib/libbluetooth-internal.la
+
+tools_3dsp_SOURCES = tools/3dsp.c monitor/bt.h
+tools_3dsp_LDADD = src/libshared-mainloop.la
+
+tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_mgmt_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_bnep_tester_SOURCES = tools/bnep-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_bnep_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_smp_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_gap_tester_LDADD = lib/libbluetooth-internal.la \
+ gdbus/libgdbus-internal.la \
+ src/libshared-glib.la \
+ @GLIB_LIBS@ @DBUS_LIBS@
+
+tools_sco_tester_SOURCES = tools/sco-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_sco_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
+tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+endif
+
+if TOOLS
+bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
+ tools/rfcomm tools/rctest tools/l2test tools/l2ping \
+ tools/sdptool tools/ciptool tools/bccmd \
+ tools/bluemoon tools/hex2hcd tools/mpris-proxy
+
+tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+ tools/hciattach_st.c \
+ tools/hciattach_ti.c \
+ tools/hciattach_tialt.c \
+ tools/hciattach_ath3k.c \
+ tools/hciattach_qualcomm.c \
+ tools/hciattach_intel.c \
+ tools/hciattach_bcm43xx.c
+tools_hciattach_LDADD = lib/libbluetooth-internal.la
+
+tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
+tools_hciconfig_LDADD = lib/libbluetooth-internal.la
+
+tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c
+tools_hcitool_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
+
+tools_hcidump_SOURCES = tools/hcidump.c \
+ tools/parser/parser.h tools/parser/parser.c \
+ tools/parser/lmp.c \
+ tools/parser/hci.c \
+ tools/parser/l2cap.h tools/parser/l2cap.c \
+ tools/parser/amp.c \
+ tools/parser/smp.c \
+ tools/parser/att.c \
+ tools/parser/sdp.h tools/parser/sdp.c \
+ tools/parser/rfcomm.h tools/parser/rfcomm.c \
+ tools/parser/bnep.c \
+ tools/parser/cmtp.c \
+ tools/parser/hidp.c \
+ tools/parser/hcrp.c \
+ tools/parser/avdtp.c \
+ tools/parser/avctp.c \
+ tools/parser/avrcp.c \
+ tools/parser/sap.c \
+ tools/parser/obex.c \
+ tools/parser/capi.c \
+ tools/parser/ppp.c \
+ tools/parser/tcpip.c \
+ tools/parser/ericsson.c \
+ tools/parser/csr.c \
+ tools/parser/bpa.c
+tools_hcidump_LDADD = lib/libbluetooth-internal.la
+
+tools_rfcomm_LDADD = lib/libbluetooth-internal.la
+
+tools_rctest_LDADD = lib/libbluetooth-internal.la
+
+tools_l2test_LDADD = lib/libbluetooth-internal.la
+
+tools_l2ping_LDADD = lib/libbluetooth-internal.la
+
+tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
+tools_sdptool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_ciptool_LDADD = lib/libbluetooth-internal.la
+
+tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
+ tools/csr_hci.c tools/csr_usb.c \
+ tools/csr_h4.c tools/csr_3wire.c \
+ tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+tools_bccmd_LDADD = lib/libbluetooth-internal.la
+
+tools_bluemoon_SOURCES = tools/bluemoon.c monitor/bt.h
+tools_bluemoon_LDADD = src/libshared-mainloop.la
+
+tools_hex2hcd_SOURCES = tools/hex2hcd.c
+
+tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
+tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+
+dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
+ tools/hcitool.1 tools/hcidump.1 \
+ tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+ tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+else
+EXTRA_DIST += tools/hciattach.1 tools/hciconfig.1 \
+ tools/hcitool.1 tools/hcidump.1 \
+ tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+ tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+endif
+
+if HID2HCI
+udevdir = @UDEV_DIR@
+
+udev_PROGRAMS = tools/hid2hci
+
+tools_hid2hci_LDADD = @UDEV_LIBS@
+
+dist_man_MANS += tools/hid2hci.1
+else
+EXTRA_DIST += tools/hid2hci.1
+endif
+
+if EXPERIMENTAL
+bin_PROGRAMS += tools/btattach
+
+noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
+ tools/scotest tools/amptest tools/hwdb \
+ tools/hcieventmask tools/hcisecfilter \
+ tools/btinfo \
+ tools/btsnoop tools/btproxy \
+ tools/btiotest tools/bneptest tools/mcaptest \
+ tools/cltest tools/oobtest tools/seq2bseq \
+ tools/nokfw tools/create-image \
+ tools/eddystone tools/ibeacon \
+ tools/btgatt-client tools/btgatt-server \
+ tools/test-runner tools/check-selftest
+
+tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
+tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
+
+tools_avinfo_LDADD = lib/libbluetooth-internal.la
+
+tools_avtest_LDADD = lib/libbluetooth-internal.la
+
+tools_scotest_LDADD = lib/libbluetooth-internal.la
+
+tools_amptest_LDADD = lib/libbluetooth-internal.la
+
+tools_hwdb_LDADD = lib/libbluetooth-internal.la
+
+tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
+
+tools_btinfo_SOURCES = tools/btinfo.c monitor/bt.h
+tools_btinfo_LDADD = src/libshared-mainloop.la
+
+tools_btattach_SOURCES = tools/btattach.c monitor/bt.h
+tools_btattach_LDADD = src/libshared-mainloop.la
+
+tools_btsnoop_SOURCES = tools/btsnoop.c
+tools_btsnoop_LDADD = src/libshared-mainloop.la
+
+tools_btproxy_SOURCES = tools/btproxy.c monitor/bt.h
+tools_btproxy_LDADD = src/libshared-mainloop.la
+
+tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
+tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_mcaptest_SOURCES = tools/mcaptest.c \
+ btio/btio.h btio/btio.c \
+ src/log.c src/log.h \
+ profiles/health/mcap.h profiles/health/mcap.c
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
+
+tools_bneptest_SOURCES = tools/bneptest.c \
+ btio/btio.h btio/btio.c \
+ src/log.h src/log.c \
+ profiles/network/bnep.h profiles/network/bnep.c
+tools_bneptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_cltest_SOURCES = tools/cltest.c
+tools_cltest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+tools_oobtest_SOURCES = tools/oobtest.c
+tools_oobtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+
+tools_seq2bseq_SOURCES = tools/seq2bseq.c
+
+tools_nokfw_SOURCES = tools/nokfw.c
+
+tools_create_image_SOURCES = tools/create-image.c
+
+tools_eddystone_SOURCES = tools/eddystone.c monitor/bt.h
+tools_eddystone_LDADD = src/libshared-mainloop.la
+
+tools_ibeacon_SOURCES = tools/ibeacon.c monitor/bt.h
+tools_ibeacon_LDADD = src/libshared-mainloop.la
+
+tools_btgatt_client_SOURCES = tools/btgatt-client.c src/uuid-helper.c
+tools_btgatt_client_LDADD = src/libshared-mainloop.la \
+ lib/libbluetooth-internal.la
+
+tools_btgatt_server_SOURCES = tools/btgatt-server.c src/uuid-helper.c
+tools_btgatt_server_LDADD = src/libshared-mainloop.la \
+ lib/libbluetooth-internal.la
+
+dist_man_MANS += tools/btattach.1
+
+EXTRA_DIST += tools/bdaddr.1
+else
+EXTRA_DIST += tools/btattach.1
+endif
+
+if READLINE
+noinst_PROGRAMS += attrib/gatttool tools/btmgmt \
+ tools/obex-client-tool tools/obex-server-tool \
+ tools/bluetooth-player tools/obexctl
+
+attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
+ attrib/gattrib.c btio/btio.c \
+ attrib/gatttool.h attrib/interactive.c \
+ attrib/utils.c src/log.c client/display.c \
+ client/display.h
+attrib_gatttool_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@ -lreadline
+
+tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+ tools/obex-client-tool.c
+tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
+ @GLIB_LIBS@ -lreadline
+
+tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+ tools/obex-server-tool.c
+tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \
+ client/display.h client/display.c
+tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \
+ @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_obexctl_SOURCES = tools/obexctl.c \
+ client/display.h client/display.c
+tools_obexctl_LDADD = gdbus/libgdbus-internal.la \
+ @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \
+ -lreadline
+endif
+
+if EXPERIMENTAL
+noinst_PROGRAMS += tools/gatt-service
+
+tools_gatt_service_SOURCES = tools/gatt-service.c
+tools_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
+
+noinst_PROGRAMS += profiles/iap/iapd
+
+profiles_iap_iapd_SOURCES = profiles/iap/main.c
+profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+endif
+
+if CUPS
+cupsdir = $(libdir)/cups/backend
+
+cups_PROGRAMS = profiles/cups/bluetooth
+
+profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \
+ profiles/cups/cups.h \
+ profiles/cups/sdp.c \
+ profiles/cups/spp.c \
+ profiles/cups/hcrp.c
+
+profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+ lib/libbluetooth-internal.la \
+ gdbus/libgdbus-internal.la
+endif
+
+test_scripts += test/sap_client.py test/bluezutils.py \
+ test/dbusdef.py test/monitor-bluetooth test/list-devices \
+ test/test-discovery test/test-manager test/test-adapter \
+ test/test-device test/simple-agent \
+ test/simple-endpoint test/test-sap-server \
+ test/test-proximity test/test-network \
+ test/test-thermometer test/test-profile test/test-health \
+ test/test-health-sink test/service-record.dtd \
+ test/service-did.xml test/service-spp.xml test/service-opp.xml \
+ test/service-ftp.xml test/simple-player test/test-nap \
+ test/test-heartrate test/test-alert test/test-hfp \
+ test/test-cyclingspeed test/opp-client test/ftp-client \
+ test/pbap-client test/map-client test/example-advertisement \
+ test/example-gatt-server test/example-gatt-client \
+ test/test-gatt-profile
diff --git a/repo/NEWS b/repo/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/repo/NEWS
diff --git a/repo/README b/repo/README
new file mode 100644
index 0000000..c991ab0
--- /dev/null
+++ b/repo/README
@@ -0,0 +1,127 @@
+BlueZ - Bluetooth protocol stack for Linux
+******************************************
+
+Copyright (C) 2000-2001 Qualcomm Incorporated
+Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
+
+
+Compilation and installation
+============================
+
+In order to compile Bluetooth utilities you need following software packages:
+ - GCC compiler
+ - GLib library
+ - D-Bus library
+ - udev library (optional)
+ - readline (command line clients)
+
+To configure run:
+ ./configure --prefix=/usr --mandir=/usr/share/man \
+ --sysconfdir=/etc --localstatedir=/var
+
+Configure automatically searches for all required components and packages.
+
+To compile and install run:
+ make && make install
+
+
+Configuration and options
+=========================
+
+For a working system, certain configuration options need to be enabled:
+
+ --enable-library
+
+ Enable installation of Bluetooth library
+
+ By default the Bluetooth library is no longer installed.
+
+ The user interfaces or command line utilities do not
+ require an installed Bluetooth library anymore. This
+ option is provided for legacy third party applications
+ that still depend on the library.
+
+ When the library installation is enabled, it is a good
+ idea to use a separate bluez-library or libbluetooth
+ package for it.
+
+ --disable-tools
+
+ Disable support for Bluetooth utilities
+
+ By default the Bluetooth utilities are built and also
+ installed. For production systems the tools are not
+ needed and this option allows to disable them to save
+ build time and disk space.
+
+ When the tools are selected, it is a good idea to
+ use a separate bluez-tools package for them.
+
+ --disable-cups
+
+ Disable support for CUPS printer backend
+
+ By default the printer backend for CUPS is build and
+ also installed. For systems that do not require printing
+ over Bluetooth, this options allows to disable it.
+
+ When the CUPS backend is selected, it is a good idea to
+ use a separate bluez-cups package for it.
+
+ --disable-monitor
+
+ Disable support for the Bluetooth monitor utility
+
+ By default the monitor utility is enabled. It provides
+ support for HCI level tracing and debugging. For systems
+ that don't require any kind of tracing or debugging
+ capabilities, this options allows to disable it.
+
+ The monitor utility should be placed in the main package
+ along with the daemons. It is universally useful.
+
+ --disable-client
+
+ Disable support for the command line client
+
+ By default the command line client is enabled and uses the
+ readline library. For specific systems where BlueZ is
+ configured by other means, the command line client can be
+ disabled and the dependency on readline is removed.
+
+ The client should be placed in the main package along
+ with the daemons. It is universally useful.
+
+ --disable-systemd
+
+ Disable integration with systemd
+
+ By default the integration with systemd is enabled and
+ installed. This gives the best integration into all
+ distributions based on systemd.
+
+ This option is provided for distributions that do not
+ support systemd. In that case all integration with the
+ init system is up to the package.
+
+ --enable-experimental
+
+ Enable experimental plugins
+
+ By default all plugins that are still in development
+ are disabled. This option can be used to enable them.
+
+ It is not recommended to enable this option for production
+ systems. The APIs or behavior of the experimental plugins
+ is unstable and might still change.
+
+
+Information
+===========
+
+Mailing lists:
+ linux-bluetooth@vger.kernel.org
+
+For additional information about the project visit BlueZ web site:
+ http://www.bluez.org
diff --git a/repo/TODO b/repo/TODO
new file mode 100644
index 0000000..8c710ef
--- /dev/null
+++ b/repo/TODO
@@ -0,0 +1,288 @@
+Background
+==========
+
+- Priority scale: High, Medium and Low
+
+- Complexity scale: C1, C2, C4 and C8. The complexity scale is exponential,
+ with complexity 1 being the lowest complexity. Complexity is a function
+ of both task 'complexity' and task 'scope'.
+
+ The general rule of thumb is that a complexity 1 task should take 1-2 weeks
+ for a person very familiar with BlueZ codebase. Higher complexity tasks
+ require more time and have higher uncertainty.
+
+ Higher complexity tasks should be refined into several lower complexity tasks
+ once the task is better understood.
+
+General
+=======
+
+- UUID handling: Use the new functions created for UUID handling in all parts
+ of BlueZ code. Currently, the new bt_uuid_* functions are being used by
+ GATT-related code only.
+
+ Priority: high
+ Complexity: C4
+
+- Update PBAP client/server implementation to 1.2 and create necessary APIs for
+ new features it introduces.
+
+ Priority: Medium
+ Complexity: C4
+
+- Create GOEP unit tests based on its test specification:
+
+ https://www.bluetooth.org/docman/handlers/DownloadDoc.ashx?doc_id=230559
+
+ Priority: Medium
+ Complexity: C2
+
+- Function in src/adapter.c to convert old storage files to new ini-file format
+ should be removed 6-8 months after first BlueZ 5 release.
+
+ Priority: Low
+ Complexity: C1
+
+- Remove usage of symlinks for drivers, such as profiles/input/suspend.c and
+ profiles/sap/sap.c. Instead, select drivers at runtime by using config
+ options or probing for running D-Bus services (using e.g.
+ g_dbus_add_service_watch()). Idea first mentioned on
+ http://thread.gmane.org/gmane.linux.bluez.kernel/30175/focus=30190.
+
+- Reuse connection handling code of src/profile.c also for built-in profiles
+ so plugins would only need to register their btd_profile and the core takes
+ care of the rest including listen to the right channel and manages the sdp
+ record. Once btd_profile manages the connection it can also notify about
+ their state, this probably remove the need of having callbacks to
+ .connect/.disconnect since their state can be tracked, it also enables any
+ plugin to track any profile state change which can be useful for e.g.
+ a connection policy plugin in case one is needed.
+
+ Priority: Low
+ Complexity: C2
+
+- Add queueing support for src/agent.c, currently if there is any request
+ pending the code fail with error EBUSY which is very inconvenient.
+
+ Priority: Low
+ Complexity: C2
+
+Low Energy
+==========
+
+- Connection modes. Adapter interface needs to be changed to manage
+ connection modes and adapter type. See Volume 3, Part C, section 9.3.
+ 1. Mode management: Peripheral / Central
+
+ Priority: Medium
+ Complexity: C2
+
+- Advertising data. The D-Bus interface needs to be updated to enable setting
+ scan response data, and to read the advertising and scan response data which
+ has been broadcast from other LE devices.
+
+ Priority: Medium
+ Complexity: C2
+
+- Static random address setup and storage. Once this address is written
+ in a given remote, the address can not be changed anymore.
+
+ Priority: Low
+ Complexity: C1
+
+- Device Name Characteristic is a GAP characteristic for Low Energy. This
+ characteristic shall be integrated/used in the discovery procedure. The
+ idea is to report the value of this characteristic using DeviceFound signals.
+ Discussion with the community is needed before to start this task. Other GAP
+ characteristics for LE needs to follow a similar approach. It is not clear
+ if all GAP characteristics can be exposed using properties instead of a primary
+ service characteristics.
+ See Volume 3, Part C, section 12.1 for more information.
+
+ Priority: Low
+ Complexity: C2
+
+ATT/GATT (new shared stack)
+===========================
+
+- Add complete GATT test coverage in unit/test-gatt following the GATT test
+ spec. This could use shared/gatt-client and shared/gatt-server at the same
+ time to test both against eachother. We should definitely have tests for
+ gatt-server and gatt-client simultaneously on one side of the connection.
+
+ Priority: High
+ Complexity: C4
+
+- Write an example using client D-Bus API using C.
+
+ Priority: High
+ Complexity: C2
+
+- Write an example using client D-Bus API using python.
+
+ Priority: High
+ Complexity: C2
+
+- Define packed structs for ATT protocol PDUs in shared/att-types to improve
+ readability. We should probably do this once there are extensive unit tests
+ for gatt-client/gatt-server so that we don't accidentally break working code.
+
+ Priority: Medium
+ Complexity: C2
+
+- Use struct iovec to pass around byte buffers that will be sent over the wire,
+ instead of passing uint8_t and size_t parameters everywhere.
+
+ Priority: Medium
+ Complexity: C1
+
+- Persist client attribute cache across reboots.
+
+ Priority: Medium
+ Complexity: C4
+
+- Move all daemon plugins and profiles that are GATT based to use
+ shared/gatt-client instead of attrib/*. This is a complicated task that
+ potentially needs a new plugin/profile probing interface and a lot of
+ rewriting that can cause regressions in existing functionality.
+
+ Priority: Medium
+ Complexity: C4
+
+- Introduce a way for shared/gatt-server to check security permissions on the
+ current connection through bt_att.
+
+ Priority: Medium
+ Complexity: C2
+
+- Implement other low-priority ATT protocol operations for shared/gatt-server:
+
+ Read Multiple Request
+
+ Priority: Low
+ Complexity: C1
+
+- Implement the server portion of doc/gatt-api.txt using shared/gatt-server once
+ it exists.
+
+ Priority: Medium
+ Complexity: C4
+
+- Send out indications from the "Service Changed" characteristic upon
+ reconnection if a bonded device is not connected when the local database is
+ modified.
+
+ Priority: High
+ Complexity: C2
+
+- Unify the GATT server and client D-Bus implementations into a single module.
+ While these don't share a lot of code, keeping them all in src/gatt-dbus seems
+ to make more sense from an organizational perspective.
+
+ Priority: Low
+ Complexity: C1
+
+- Isolate all GATT code inside the daemon into its own module and perform
+ interaction with other modules (e.g. src/device.c) via callbacks. This
+ includes client/server management, tracking incoming/outgoing connections for
+ ATT, and callbacks to perform profile probing.
+
+ Priority: Low
+ Complexity: C4
+
+- Support included services in the GATT D-Bus client API.
+
+ Priority: Medium
+ Complexity: C1
+
+- The recently added support for ATT signed writes requires the following kernel
+ modules to be enabled:
+
+ CONFIG_CRYPTO_USER_API
+ CONFIG_CRYPTO_USER_API_HASH
+ CONFIG_CRYPTO_USER_API_SKCIPHER
+
+ Currently, if these are not enabled, bt_att_new silently returns NULL. We
+ should handle this more gracefully by not supporting signed writes if we can't
+ initialize bt_crypto while succeeding bt_att initialization regardless.
+
+ This behavior should be documented in the README.
+
+ Priority: High
+ Complexity: C1
+
+
+ATT/GATT (old/outdated)
+=======================
+
+- At the moment authentication and authorization is not supported at the
+ same time, read/write requirements in the attribute server needs to
+ be extended. According to Bluetooth Specification a server shall check
+ authentication and authorization requirements before any other check is
+ performed.
+
+ Priority: Medium
+ Complexity: C1
+
+- Implement ATT PDU validation. Malformed PDUs can cause division by zero
+ when decoding PDUs. A proper error PDU should be returned for this case.
+ See decoding function in att.c file.
+
+ Priority: Medium
+ Complexity: C1
+
+- Refactor read_by_group() and read_by_type() in src/attrib-server.c
+ (they've grown simply too big). First step could be to move out the
+ long for-loops to new functions called e.g. get_groups() and get_types().
+
+ Priority: Low
+ Complexity: C1
+
+- Agent for characteristics: Agent interface should be extended to support
+ authorization per characteristic if the remote is not in the trusted list.
+
+ Priority: Low
+ Complexity: C1
+
+- gatttool should have the ability to wait for req responses before
+ quitting (some servers require a small sleep even with cmd's). Maybe a
+ --delay-exit or --timeout command line switch.
+
+ Priority: Low
+ Complexity: C1
+
+- Client needs to export a property in the Device Characteristic hierarchy
+ to manage characteristic value changes reports in the remote device.
+ Currently, Client Characteristic Configuration attribute is not exposed
+ as an object. The user needs to use gatttool to change the value of the
+ this attribute to receive notification/indications. Export this attribute
+ as a property is a proposal that needs further discussion.
+
+ Priority: Low
+ Complexity: C1
+
+- Attribute server should process queued GATT/ATT commands if the
+ client disconnects. The client can simply send a command and quit,
+ without wait for a response(ex: Write Command). For this scenario
+ that the client disconnects the link quickly the queued received
+ command is ignored.
+
+ Priority: Low
+ Complecity: C1
+
+- Implement Server characteristic Configuration support in the attribute
+ server to manage characteristic value broadcasting. There is a single
+ instance of the Server Characteristic Configuration for all clients.
+ See Volume 3, Part G, section 3.3.3.4 for more information.
+
+ Priority: Low
+ Complexity: C1
+
+- Long write is not implemented. Attribute server, client and command line
+ tool shall be changed to support this feature.
+
+ Priority: Low
+ Complexity: C2
+
+Management Interface
+====================
diff --git a/repo/acinclude.m4 b/repo/acinclude.m4
new file mode 100644
index 0000000..bc39c6d
--- /dev/null
+++ b/repo/acinclude.m4
@@ -0,0 +1,62 @@
+AC_DEFUN([AC_PROG_CC_PIE], [
+ AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_pie=yes
+ else
+ ac_cv_prog_cc_pie=no
+ fi
+ rm -rf conftest*
+ ])
+])
+
+AC_DEFUN([COMPILER_FLAGS], [
+ with_cflags=""
+ if (test "$USE_MAINTAINER_MODE" = "yes"); then
+ with_cflags="$with_cflags -Wall -Werror -Wextra"
+ with_cflags="$with_cflags -Wno-unused-parameter"
+ with_cflags="$with_cflags -Wno-missing-field-initializers"
+ with_cflags="$with_cflags -Wdeclaration-after-statement"
+ with_cflags="$with_cflags -Wmissing-declarations"
+ with_cflags="$with_cflags -Wredundant-decls"
+ with_cflags="$with_cflags -Wcast-align"
+ with_cflags="$with_cflags -Wswitch-enum"
+ with_cflags="$with_cflags -Wformat -Wformat-security"
+ with_cflags="$with_cflags -DG_DISABLE_DEPRECATED"
+ with_cflags="$with_cflags -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_28"
+ with_cflags="$with_cflags -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_28"
+ fi
+ AC_SUBST([WARNING_CFLAGS], $with_cflags)
+])
+
+AC_DEFUN([MISC_FLAGS], [
+ misc_cflags=""
+ misc_ldflags=""
+ AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
+ [disable code optimization through compiler]), [
+ if (test "${enableval}" = "no"); then
+ misc_cflags="$misc_cflags -O0"
+ fi
+ ])
+ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
+ [enable compiling with debugging information]), [
+ if (test "${enableval}" = "yes" &&
+ test "${ac_cv_prog_cc_g}" = "yes"); then
+ misc_cflags="$misc_cflags -g"
+ fi
+ ])
+ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
+ [enable position independent executables flag]), [
+ if (test "${enableval}" = "yes" &&
+ test "${ac_cv_prog_cc_pie}" = "yes"); then
+ misc_cflags="$misc_cflags -fPIC"
+ misc_ldflags="$misc_ldflags -pie"
+ fi
+ ])
+ if (test "$enable_coverage" = "yes"); then
+ misc_cflags="$misc_cflags --coverage"
+ misc_ldflags="$misc_ldflags --coverage"
+ fi
+ AC_SUBST([MISC_CFLAGS], $misc_cflags)
+ AC_SUBST([MISC_LDFLAGS], $misc_ldflags)
+])
diff --git a/repo/android/Android.mk b/repo/android/Android.mk
new file mode 100644
index 0000000..38ef4aa
--- /dev/null
+++ b/repo/android/Android.mk
@@ -0,0 +1,855 @@
+LOCAL_PATH := external/bluetooth
+
+# Retrieve BlueZ version from configure.ac file
+BLUEZ_VERSION := `grep "^AC_INIT" $(LOCAL_PATH)/bluez/configure.ac | sed -e "s/.*,.\(.*\))/\1/"`
+
+ANDROID_VERSION := $(shell echo $(PLATFORM_VERSION) | awk -F. '{ printf "0x%02d%02d%02d",$$1,$$2,$$3 }')
+
+ANDROID_GE_5_0_0 := $(shell test `echo $$(($(ANDROID_VERSION)))` -lt `echo $$((0x050000))`; echo $$?)
+
+# Specify pathmap for glib and sbc
+pathmap_INCL += glib:external/bluetooth/glib \
+ sbc:external/bluetooth/sbc \
+
+# Specify common compiler flags
+BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
+ -DANDROID_VERSION=$(ANDROID_VERSION) \
+ -DANDROID_STORAGEDIR=\"/data/misc/bluetooth\" \
+ -DHAVE_LINUX_IF_ALG_H \
+ -DHAVE_LINUX_TYPES_H \
+
+# Enable warnings enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wall -Wextra \
+ -Wdeclaration-after-statement \
+ -Wmissing-declarations \
+ -Wredundant-decls \
+ -Wcast-align \
+
+# Disable warnings enabled by Android but not enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wno-pointer-arith \
+ -Wno-missing-field-initializers \
+ -Wno-unused-parameter \
+
+#
+# Android BlueZ daemon (bluetoothd)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/main.c \
+ bluez/android/bluetooth.c \
+ bluez/profiles/scanparam/scpp.c \
+ bluez/profiles/deviceinfo/dis.c \
+ bluez/profiles/battery/bas.c \
+ bluez/profiles/input/hog-lib.c \
+ bluez/android/hidhost.c \
+ bluez/android/socket.c \
+ bluez/android/ipc.c \
+ bluez/android/avdtp.c \
+ bluez/android/a2dp.c \
+ bluez/android/a2dp-sink.c \
+ bluez/android/avctp.c \
+ bluez/android/avrcp.c \
+ bluez/android/avrcp-lib.c \
+ bluez/android/pan.c \
+ bluez/android/handsfree.c \
+ bluez/android/handsfree-client.c \
+ bluez/android/gatt.c \
+ bluez/android/health.c \
+ bluez/android/sco.c \
+ bluez/profiles/health/mcap.c \
+ bluez/android/map-client.c \
+ bluez/android/log.c \
+ bluez/src/shared/mgmt.c \
+ bluez/src/shared/util.c \
+ bluez/src/shared/queue.c \
+ bluez/src/shared/ringbuf.c \
+ bluez/src/shared/hfp.c \
+ bluez/src/shared/gatt-db.c \
+ bluez/src/shared/io-glib.c \
+ bluez/src/shared/timeout-glib.c \
+ bluez/src/shared/crypto.c \
+ bluez/src/shared/uhid.c \
+ bluez/src/shared/att.c \
+ bluez/src/sdpd-database.c \
+ bluez/src/sdpd-service.c \
+ bluez/src/sdpd-request.c \
+ bluez/src/sdpd-server.c \
+ bluez/src/uuid-helper.c \
+ bluez/src/eir.c \
+ bluez/lib/sdp.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/lib/uuid.c \
+ bluez/btio/btio.c \
+ bluez/src/sdp-client.c \
+ bluez/profiles/network/bnep.c \
+ bluez/attrib/gattrib.c \
+ bluez/attrib/gatt.c \
+ bluez/attrib/att.c
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, glib) \
+ $(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+ libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_TAGS := optional
+
+# for userdebug/eng this module is bluetoothd-main since bluetoothd is used as
+# wrapper to launch bluetooth with Valgrind
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_MODULE := bluetoothd-main
+LOCAL_STRIP_MODULE := false
+else
+LOCAL_MODULE := bluetoothd
+endif
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bluetooth.default.so HAL
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/hal-ipc.c \
+ bluez/android/hal-bluetooth.c \
+ bluez/android/hal-socket.c \
+ bluez/android/hal-hidhost.c \
+ bluez/android/hal-pan.c \
+ bluez/android/hal-a2dp.c \
+ bluez/android/hal-avrcp.c \
+ bluez/android/hal-handsfree.c \
+ bluez/android/hal-gatt.c \
+ bluez/android/hal-utils.c \
+ bluez/android/hal-health.c \
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_SRC_FILES += \
+ bluez/android/hal-handsfree-client.c \
+ bluez/android/hal-map-client.c \
+ bluez/android/hal-a2dp-sink.c \
+ bluez/android/hal-avrcp-ctrl.c
+endif
+
+LOCAL_C_INCLUDES += \
+ $(call include-path-for, system-core) \
+ $(call include-path-for, libhardware) \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE := bluetooth.default
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_REQUIRED_MODULES := bluetoothd bluetoothd-snoop init.bluetooth.rc
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# haltest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/client/haltest.c \
+ bluez/android/client/pollhandler.c \
+ bluez/android/client/terminal.c \
+ bluez/android/client/history.c \
+ bluez/android/client/tabcompletion.c \
+ bluez/android/client/if-audio.c \
+ bluez/android/client/if-sco.c \
+ bluez/android/client/if-av.c \
+ bluez/android/client/if-rc.c \
+ bluez/android/client/if-bt.c \
+ bluez/android/client/if-hf.c \
+ bluez/android/client/if-hh.c \
+ bluez/android/client/if-pan.c \
+ bluez/android/client/if-hl.c \
+ bluez/android/client/if-sock.c \
+ bluez/android/client/if-gatt.c \
+ bluez/android/hal-utils.c \
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_SRC_FILES += \
+ bluez/android/client/if-hf-client.c \
+ bluez/android/client/if-mce.c \
+ bluez/android/client/if-av-sink.c \
+ bluez/android/client/if-rc-ctrl.c
+endif
+
+LOCAL_C_INCLUDES += \
+ $(call include-path-for, system-core) \
+ $(call include-path-for, libhardware) \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bluez/android \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+
+LOCAL_SHARED_LIBRARIES := \
+ libhardware \
+ libcutils \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := haltest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# mcaptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/src/log.c \
+ bluez/btio/btio.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/profiles/health/mcap.c \
+ bluez/tools/mcaptest.c \
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, glib) \
+ $(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+ libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := mcaptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bneptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/src/log.c \
+ bluez/btio/btio.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/profiles/network/bnep.c \
+ bluez/tools/bneptest.c \
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, glib) \
+ $(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+ libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := bneptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# avdtptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/avdtptest.c \
+ bluez/android/avdtp.c \
+ bluez/src/log.c \
+ bluez/btio/btio.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/src/shared/util.c \
+ bluez/src/shared/queue.c \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bluez \
+ $(call include-path-for, glib) \
+ $(call include-path-for, glib)/glib \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+ libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avdtptest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# btmon
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/monitor/main.c \
+ bluez/monitor/display.c \
+ bluez/monitor/hcidump.c \
+ bluez/monitor/control.c \
+ bluez/monitor/packet.c \
+ bluez/monitor/l2cap.c \
+ bluez/monitor/avctp.c \
+ bluez/monitor/avdtp.c \
+ bluez/monitor/a2dp.c \
+ bluez/monitor/rfcomm.c \
+ bluez/monitor/bnep.c \
+ bluez/monitor/uuid.c \
+ bluez/monitor/sdp.c \
+ bluez/monitor/vendor.c \
+ bluez/monitor/lmp.c \
+ bluez/monitor/crc.c \
+ bluez/monitor/ll.c \
+ bluez/monitor/hwdb.c \
+ bluez/monitor/keys.c \
+ bluez/monitor/ellisys.c \
+ bluez/monitor/analyze.c \
+ bluez/monitor/intel.c \
+ bluez/monitor/broadcom.c \
+ bluez/src/shared/util.c \
+ bluez/src/shared/queue.c \
+ bluez/src/shared/crypto.c \
+ bluez/src/shared/btsnoop.c \
+ bluez/src/shared/mainloop.c \
+ bluez/lib/hci.c \
+ bluez/lib/bluetooth.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btmon
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# btproxy
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/btproxy.c \
+ bluez/src/shared/mainloop.c \
+ bluez/src/shared/util.c \
+ bluez/src/shared/ecc.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btproxy
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# A2DP audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/hal-audio.c \
+ bluez/android/hal-audio-sbc.c \
+ bluez/android/hal-audio-aptx.c \
+
+LOCAL_C_INCLUDES = \
+ $(LOCAL_PATH)/bluez \
+ $(call include-path-for, system-core) \
+ $(call include-path-for, libhardware) \
+ $(call include-path-for, sbc) \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libsbc \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+LOCAL_LDFLAGS := -ldl
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.a2dp.default
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# SCO audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bluez/android/hal-sco.c \
+ bluez/android/hal-utils.c
+
+LOCAL_C_INCLUDES = \
+ $(call include-path-for, system-core) \
+ $(call include-path-for, libhardware) \
+ $(call include-path-for, audio-utils) \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libaudioutils \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.sco.default
+
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# l2cap-test
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/l2test.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := l2test
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bluetoothd-snoop
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/bluetoothd-snoop.c \
+ bluez/src/shared/mainloop.c \
+ bluez/src/shared/btsnoop.c \
+ bluez/android/log.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+ $(LOCAL_PATH)/bluez/lib \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothd-snoop
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# init.bluetooth.rc
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init.bluetooth.rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := bluez/android/$(LOCAL_MODULE)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+
+include $(BUILD_PREBUILT)
+
+#
+# btmgmt
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/btmgmt.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/lib/sdp.c \
+ bluez/src/shared/mainloop.c \
+ bluez/src/shared/io-mainloop.c \
+ bluez/src/shared/mgmt.c \
+ bluez/src/shared/queue.c \
+ bluez/src/shared/util.c \
+ bluez/src/shared/gap.c \
+ bluez/src/uuid-helper.c \
+ bluez/client/display.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+ $(LOCAL_PATH)/bluez/android/compat \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := btmgmt
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hcitool
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/hcitool.c \
+ bluez/src/oui.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := hcitool
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hciconfig
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ bluez/tools/hciconfig.c \
+ bluez/tools/csr.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := hciconfig
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# l2ping
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/l2ping.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := l2ping
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# avtest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/avtest.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avtest
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# hciattach
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/hciattach.c \
+ bluez/tools/hciattach_st.c \
+ bluez/tools/hciattach_ti.c \
+ bluez/tools/hciattach_tialt.c \
+ bluez/tools/hciattach_ath3k.c \
+ bluez/tools/hciattach_qualcomm.c \
+ bluez/tools/hciattach_intel.c \
+ bluez/tools/hciattach_bcm43xx.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := hciattach
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# libsbc
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ sbc/sbc/sbc.c \
+ sbc/sbc/sbc_primitives.c \
+ sbc/sbc/sbc_primitives_mmx.c \
+ sbc/sbc/sbc_primitives_neon.c \
+ sbc/sbc/sbc_primitives_armv6.c \
+ sbc/sbc/sbc_primitives_iwmmxt.c \
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/sbc \
+
+LOCAL_CFLAGS:= \
+ -Os \
+ -Wno-sign-compare \
+ -Wno-missing-field-initializers \
+ -Wno-unused-parameter \
+ -Wno-type-limits \
+ -Wno-empty-body \
+
+LOCAL_MODULE := libsbc
+
+include $(BUILD_SHARED_LIBRARY)
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+
+#
+# bluetoothd (debug)
+# this is just a wrapper used in userdebug/eng to launch bluetoothd-main
+# with/without Valgrind
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/android/bluetoothd-wrapper.c \
+ bluez/android/hal-utils.c
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothd
+
+LOCAL_REQUIRED_MODULES := \
+ bluetoothd-main \
+ valgrind \
+ memcheck-$(TARGET_ARCH)-linux \
+ vgpreload_core-$(TARGET_ARCH)-linux \
+ vgpreload_memcheck-$(TARGET_ARCH)-linux \
+ default.supp
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+#
+# bluetooth-headers
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bluetooth-headers
+LOCAL_NODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+include_path := $(local-intermediates-dir)/include
+include_files := $(wildcard $(LOCAL_PATH)/bluez/lib/*.h)
+$(shell mkdir -p $(include_path)/bluetooth)
+$(foreach file,$(include_files),$(shell cp -u $(file) $(include_path)/bluetooth))
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(include_path)
+
+include $(BUILD_STATIC_LIBRARY)
+
+#
+# avtest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/avinfo.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := avinfo
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
+# rctest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bluez/tools/rctest.c \
+ bluez/lib/bluetooth.c \
+ bluez/lib/hci.c \
+ bluez/lib/sdp.c \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+ bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := rctest
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
diff --git a/repo/android/Makefile.am b/repo/android/Makefile.am
new file mode 100644
index 0000000..154f8db
--- /dev/null
+++ b/repo/android/Makefile.am
@@ -0,0 +1,320 @@
+if ANDROID
+
+AM_CFLAGS += -DANDROID_VERSION=0x050100
+
+android_plugindir = $(abs_top_srcdir)/android/.libs
+
+noinst_PROGRAMS += android/system-emulator
+
+android_system_emulator_SOURCES = android/system-emulator.c
+android_system_emulator_LDADD = src/libshared-mainloop.la
+
+noinst_PROGRAMS += android/bluetoothd-snoop
+
+android_bluetoothd_snoop_SOURCES = android/bluetoothd-snoop.c src/log.c
+android_bluetoothd_snoop_LDADD = src/libshared-mainloop.la @GLIB_LIBS@
+
+noinst_PROGRAMS += android/bluetoothd
+
+android_bluetoothd_SOURCES = android/main.c \
+ src/log.c \
+ android/hal-msg.h \
+ android/audio-msg.h \
+ android/sco-msg.h \
+ android/utils.h \
+ src/sdpd-database.c src/sdpd-server.c \
+ src/sdpd-service.c src/sdpd-request.c \
+ src/uuid-helper.h src/uuid-helper.c \
+ src/eir.h src/eir.c \
+ android/bluetooth.h android/bluetooth.c \
+ android/hidhost.h android/hidhost.c \
+ profiles/scanparam/scpp.h \
+ profiles/scanparam/scpp.c \
+ profiles/deviceinfo/dis.h \
+ profiles/deviceinfo/dis.c \
+ profiles/battery/bas.h profiles/battery/bas.c \
+ profiles/input/hog-lib.h \
+ profiles/input/hog-lib.c \
+ android/ipc-common.h \
+ android/ipc.h android/ipc.c \
+ android/avdtp.h android/avdtp.c \
+ android/a2dp.h android/a2dp.c \
+ android/a2dp-sink.h android/a2dp-sink.c \
+ android/avctp.h android/avctp.c \
+ android/avrcp.h android/avrcp.c \
+ android/avrcp-lib.h android/avrcp-lib.c \
+ android/socket.h android/socket.c \
+ android/sco.h android/sco.c \
+ android/pan.h android/pan.c \
+ android/handsfree.h android/handsfree.c \
+ android/handsfree-client.c android/handsfree-client.h \
+ android/gatt.h android/gatt.c \
+ android/health.h android/health.c \
+ profiles/health/mcap.h profiles/health/mcap.c \
+ android/map-client.h android/map-client.c \
+ attrib/att.c attrib/att.h \
+ attrib/gatt.c attrib/gatt.h \
+ attrib/gattrib.c attrib/gattrib.h \
+ btio/btio.h btio/btio.c \
+ src/sdp-client.h src/sdp-client.c \
+ profiles/network/bnep.h profiles/network/bnep.c
+android_bluetoothd_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+plugin_LTLIBRARIES += android/bluetooth.default.la
+
+android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
+ android/hal-socket.c \
+ android/hal-hidhost.c \
+ android/hal-health.c \
+ android/hal-pan.c \
+ android/hal-a2dp.c \
+ android/hal-a2dp-sink.c \
+ android/hal-avrcp.c \
+ android/hal-avrcp-ctrl.c \
+ android/hal-handsfree.c \
+ android/hal-handsfree-client.c \
+ android/hal-gatt.c \
+ android/hal-map-client.c \
+ android/hardware/bluetooth.h \
+ android/hardware/bt_av.h \
+ android/hardware/bt_gatt.h \
+ android/hardware/bt_gatt_client.h \
+ android/hardware/bt_gatt_server.h \
+ android/hardware/bt_gatt_types.h \
+ android/hardware/bt_hf.h \
+ android/hardware/bt_hh.h \
+ android/hardware/bt_hl.h \
+ android/hardware/bt_pan.h \
+ android/hardware/bt_rc.h \
+ android/hardware/bt_sock.h \
+ android/hardware/bt_hf_client.h \
+ android/hardware/bt_mce.h \
+ android/hardware/hardware.h \
+ android/cutils/properties.h \
+ android/ipc-common.h \
+ android/hal-log.h \
+ android/hal-ipc.h android/hal-ipc.c \
+ android/hal-utils.h android/hal-utils.c
+android_bluetooth_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_bluetooth_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+ -no-undefined
+
+noinst_PROGRAMS += android/avdtptest
+
+android_avdtptest_SOURCES = android/avdtptest.c \
+ src/log.h src/log.c \
+ btio/btio.h btio/btio.c \
+ src/shared/util.h src/shared/util.c \
+ src/shared/queue.h src/shared/queue.c \
+ android/avdtp.h android/avdtp.c
+android_avdtptest_CFLAGS = $(AM_CFLAGS)
+android_avdtptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+noinst_PROGRAMS += android/haltest
+
+android_haltest_SOURCES = android/client/haltest.c \
+ android/client/pollhandler.h \
+ android/client/pollhandler.c \
+ android/client/terminal.h \
+ android/client/terminal.c \
+ android/client/history.h \
+ android/client/history.c \
+ android/client/tabcompletion.c \
+ android/client/if-main.h \
+ android/client/if-av.c \
+ android/client/if-av-sink.c \
+ android/client/if-rc.c \
+ android/client/if-rc-ctrl.c \
+ android/client/if-bt.c \
+ android/client/if-gatt.c \
+ android/client/if-hf.c \
+ android/client/if-hf-client.c \
+ android/client/if-hh.c \
+ android/client/if-pan.c \
+ android/client/if-hl.c \
+ android/client/if-sock.c \
+ android/client/if-audio.c \
+ android/client/if-sco.c \
+ android/client/if-mce.c \
+ android/hardware/hardware.c \
+ android/hal-utils.h android/hal-utils.c
+android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+ -DPLUGINDIR=\""$(android_plugindir)"\"
+android_haltest_LDFLAGS = -pthread -ldl -lm
+
+noinst_PROGRAMS += android/android-tester
+
+android_android_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c \
+ monitor/rfcomm.h \
+ android/hardware/hardware.c \
+ android/tester-bluetooth.c \
+ android/tester-socket.c \
+ android/tester-hidhost.c \
+ android/tester-pan.c \
+ android/tester-hdp.c \
+ android/tester-a2dp.c \
+ android/tester-avrcp.c \
+ android/tester-gatt.c \
+ android/tester-map-client.c \
+ android/tester-main.h android/tester-main.c
+android_android_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+ -DPLUGINDIR=\""$(android_plugindir)"\"
+android_android_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+android_android_tester_LDFLAGS = -pthread -ldl
+
+noinst_PROGRAMS += android/ipc-tester
+
+android_ipc_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c \
+ android/hal-utils.h android/hal-utils.c \
+ android/ipc-common.h android/ipc-tester.c
+android_ipc_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_ipc_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
+
+plugin_LTLIBRARIES += android/audio.a2dp.default.la
+
+android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
+ android/hal-msg.h \
+ android/hal-audio.h \
+ android/hal-audio.c \
+ android/hal-audio-sbc.c \
+ android/hal-audio-aptx.c \
+ android/hardware/audio.h \
+ android/hardware/audio_effect.h \
+ android/hardware/hardware.h \
+ android/system/audio.h
+android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+ @SBC_CFLAGS@
+android_audio_a2dp_default_la_LIBADD = @SBC_LIBS@
+android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+ -no-undefined -pthread -lrt
+
+plugin_LTLIBRARIES += android/audio.sco.default.la
+
+android_audio_sco_default_la_SOURCES = android/hal-log.h \
+ android/sco-msg.h \
+ android/hal-sco.c \
+ android/hardware/audio.h \
+ android/hardware/audio_effect.h \
+ android/hardware/hardware.h \
+ android/audio_utils/resampler.c \
+ android/audio_utils/resampler.h \
+ android/system/audio.h
+android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_audio_sco_default_la_LIBADD = @SPEEXDSP_LIBS@
+android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+ -no-undefined -lrt
+unit_tests += android/test-ipc
+
+android_test_ipc_SOURCES = android/test-ipc.c \
+ src/log.h src/log.c \
+ android/ipc-common.h \
+ android/ipc.c android/ipc.h
+android_test_ipc_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+endif
+
+EXTRA_DIST += android/Android.mk android/README \
+ android/compat/readline/history.h \
+ android/compat/readline/readline.h \
+ android/compat/wordexp.h \
+ android/bluetoothd-wrapper.c \
+ android/log.c \
+ android/bluetoothd.te \
+ android/bluetoothd_snoop.te \
+ android/init.bluetooth.rc \
+ android/hal-ipc-api.txt \
+ android/audio-ipc-api.txt \
+ android/cts.txt \
+ android/pics-rfcomm.txt \
+ android/pics-spp.txt \
+ android/pics-sdp.txt \
+ android/pics-l2cap.txt \
+ android/pics-gap.txt \
+ android/pics-did.txt \
+ android/pics-hid.txt \
+ android/pics-pan.txt \
+ android/pics-opp.txt \
+ android/pics-map.txt \
+ android/pics-pbap.txt \
+ android/pics-a2dp.txt \
+ android/pics-avctp.txt \
+ android/pics-avrcp.txt \
+ android/pics-hsp.txt \
+ android/pics-hfp.txt \
+ android/pics-gatt.txt \
+ android/pics-mcap.txt \
+ android/pics-hdp.txt \
+ android/pics-iopt.txt \
+ android/pics-sm.txt \
+ android/pics-mps.txt \
+ android/pics-hogp.txt \
+ android/pics-scpp.txt \
+ android/pics-dis.txt \
+ android/pics-avdtp.txt \
+ android/pics-gavdp.txt \
+ android/pics-bnep.txt \
+ android/pixit-l2cap.txt \
+ android/pixit-gap.txt \
+ android/pixit-did.txt \
+ android/pixit-hid.txt \
+ android/pixit-pan.txt \
+ android/pixit-opp.txt \
+ android/pixit-map.txt \
+ android/pixit-pbap.txt \
+ android/pixit-a2dp.txt \
+ android/pixit-avctp.txt \
+ android/pixit-avrcp.txt \
+ android/pixit-hsp.txt \
+ android/pixit-hfp.txt \
+ android/pixit-gatt.txt \
+ android/pixit-mcap.txt \
+ android/pixit-hdp.txt \
+ android/pixit-iopt.txt \
+ android/pixit-sm.txt \
+ android/pixit-mps.txt \
+ android/pixit-hogp.txt \
+ android/pixit-scpp.txt \
+ android/pixit-dis.txt \
+ android/pixit-rfcomm.txt \
+ android/pixit-spp.txt \
+ android/pixit-avdtp.txt \
+ android/pixit-gavdp.txt \
+ android/pixit-sdp.txt \
+ android/pixit-bnep.txt \
+ android/pts-rfcomm.txt \
+ android/pts-spp.txt \
+ android/pts-l2cap.txt \
+ android/pts-gap.txt \
+ android/pts-did.txt \
+ android/pts-hid.txt \
+ android/pts-pan.txt \
+ android/pts-opp.txt \
+ android/pts-map.txt \
+ android/pts-a2dp.txt \
+ android/pts-avrcp.txt \
+ android/pts-avctp.txt \
+ android/pts-pbap.txt \
+ android/pts-hfp.txt \
+ android/pts-gatt.txt \
+ android/pts-hsp.txt \
+ android/pts-iopt.txt \
+ android/pts-hdp.txt \
+ android/pts-mcap.txt \
+ android/pts-mps.txt \
+ android/pts-sm.txt \
+ android/pts-hogp.txt \
+ android/pts-scpp.txt \
+ android/pts-dis.txt \
+ android/pts-avdtp.txt \
+ android/pts-gavdp.txt \
+ android/pts-sdp.txt \
+ android/pts-bnep.txt
diff --git a/repo/android/README b/repo/android/README
new file mode 100644
index 0000000..fa4c42a
--- /dev/null
+++ b/repo/android/README
@@ -0,0 +1,454 @@
+BlueZ for Android
+*****************
+
+Since Android 4.2 there exists a well standardized HAL interface that the
+Bluetooth stack is expected to provide and which enables the easy replacement
+of the stack of choice on Android. Android BlueZ is intended as a drop-in
+replacement to Android provided Bluetooth stack.
+
+More details about BlueZ for Android architecture and components can be found
+in android/hal-ipc-api.txt file.
+
+Supported Android version: 4.4 KitKat and 5.0, 5.1 Lollipop
+
+
+Building and running on Android
+===============================
+
+Steps needed to build and run Android Open Source Project with integrated BlueZ.
+
+
+Build requirements
+------------------
+
+- GLib - Android 4.2 or later don't provide GLib and one must provide it in
+'external/bluetooth/glib' folder of Android tree. Sample Android GLib port
+is available at https://github.com/bluez-android/glib
+
+- SBC - A2DP code requires SBC library (version 1.2 or higher) present in
+'external/bluetooth/sbc' directory. Library is build from Android.mk provided
+by BlueZ. SBC code is available at git://git.kernel.org/pub/scm/bluetooth/sbc
+
+- Bionic support - Android 5.0 provides all required functionality. Running
+BlueZ on Android 4.4 requires backporting missing features (epoll_create1 and
+ppoll calls). Sample Bionic for Android 4.4 with all required features
+backported is available at
+https://github.com/bluez-android/aosp_platform_bionic
+
+Runtime requirements
+--------------------
+
+BlueZ HAL library requires 'bluetoothd' and 'bluetoothd-snoop' services to be
+available on Android system. Some permissions settings are also required.
+
+This can be done by importing init.bluetooth.rc file in init.rc file of targeted
+board:
+import init.bluetooth.rc
+
+For convenience examples are provided at:
+https://github.com/bluez-android/aosp_device_lge_mako (Nexus 4)
+https://github.com/bluez-android/aosp_device_lge_hammerhead (Nexus 5)
+https://github.com/bluez-android/aosp_device_asus_flo (Nexus 7 2013)
+
+Security-Enhanced Linux in Android
+----------------------------------
+
+Since 5.0 release Android moved to full enforcement of SELinux. This requires
+proper policy to be provided for all BlueZ for Android services (and services
+interacting with BlueZ). Policies should be placed in external/selinux/ path.
+
+Required policy files are provided at:
+bluetoothd.te
+bluetoothd_snoop.te
+
+For convenience sepolicy.git with all required policies is available at:
+https://github.com/bluez-android/aosp_platform_external_sepolicy
+
+Downloading and building
+------------------------
+
+Building for Android requires full Android AOSP source tree. Sample Android tree
+with all required components present is available at
+https://github.com/bluez-android
+
+This tree provides support for Nexus4 (mako), Nexus 5 (hammerhead) and
+Nexus 7 2013 (flo, deb). Tree does not provide binary blobs needed to run
+Android on supported devices. Those can be obtained from
+https://developers.google.com/android/nexus/drivers. Binary blobs needs to be
+unpacked (EULA acceptance required) into 'vendor' directory of Android tree.
+
+Downloading:
+Android 5.0 - 'lollipop' branch
+Android 4.4 - 'kitkat' branch
+
+repo init -u https://github.com/bluez-android/aosp_platform_manifest \
+ -b lollipop
+repo sync
+
+Building:
+source build/envsetup.sh
+lunch aosp_<target>-userdebug
+make -j8
+
+Flashing:
+adb reboot bootloader
+fastboot flashall -w
+
+After full build is done it is possible to rebuild only BlueZ:
+'cd external/bluetooth/bluez/android/'
+'mm' (or 'mm -B' to force rebuilding of all files)
+'adb sync' to update target device.
+
+Downloading and building for Intel devices
+------------------------------------------
+
+Sample Android tree with all required components for Intel devices based on
+Intel reference image (https://01.org/android-ia) can be reconstructed following
+instructions below.
+
+This tree provides support for Dell XPS12, Minnowboard MAX, Intel NUC,
+Acer Iconia W700 and other devices mentioned in:
+https://01.org/android-ia/guides/devices
+
+Downloading:
+repo init -u https://github.com/01org/android-bluez-manifest.git -b android-ia \
+ -m topic/bluez
+repo sync
+
+Building:
+source build/envsetup.sh
+lunch haswell_generic-eng
+make -j8
+
+Installing:
+Live and Install image is $OUT/live.img
+Flash live.img to USB flash and boot from it. More instructions here:
+https://01.org/android-ia/guides/developers/build-and-install
+
+Linux Kernel requirements
+-------------------------
+
+BlueZ for Android uses Linux Bluetooth subsystem and it must be enabled in
+kernel. Minimal required version of management interface is 1.3. This
+corresponds to Linux 3.9 but latest available version is recommended. Other
+requirements include UHID and network bridge support.
+
+Following kernel options should be enabled:
+CONFIG_BT
+CONFIG_BT_RFCOMM
+CONFIG_BT_RFCOMM_TTY
+CONFIG_BT_BNEP
+CONFIG_BT_BNEP_MC_FILTER
+CONFIG_BT_BNEP_PROTO_FILTER
+CONFIG_BRIDGE
+CONFIG_UHID
+CONFIG_CRYPTO_CMAC
+CONFIG_CRYPTO_USER_API
+CONFIG_CRYPTO_USER_API_HASH
+CONFIG_CRYPTO_USER_API_SKCIPHER
+
+Also BT chip driver needs to be enabled e.g:
+CONFIG_BT_HCIBTUSB
+
+If it is not possible to use new enough Linux kernel one can use updated
+bluetooth subsystem from Backports project. More information about Backports can
+be found at https://backports.wiki.kernel.org. Sample kernels using backports
+for running BlueZ on Android are available at https://github.com/bluez-android.
+
+
+Running with Valgrind
+---------------------
+
+BlueZ for Android is preconfigured to be easily run under Valgrind memcheck.
+Appropriate configuration and required modules are automatically included when
+building either userdebug or eng variant of Android platform.
+
+Valgrind can be enabled in runtime by setting "persist.sys.bluetooth.valgrind"
+property to either literal "true" or any numeric value >0. For example:
+adb root
+adb shell setprop persist.sys.bluetooth.valgrind true
+
+After changing property value Bluetooth need to be restarted to apply changes
+(this can be done using UI, just disable and enable it again). Property is
+persistent, i.e. there's no need to enable Valgrind again after reboot.
+
+It's recommended to have unstripped libglib.so installed which will enable
+complete backtraces in Valgrind output. Otherwise, in many cases backtrace
+will break at e.g. g_free() function without prior callers. It's possible to
+have proper library installed automatically by appropriate entry in Android.mk,
+see https://github.com/bluez-android/glib for an example.
+
+When running with valgrind SElinux needs to be set into permissive mode. This
+can be done by executing 'setenforce 0' from root shell.
+
+
+Enabling BlueZ debugs
+---------------------
+
+BlueZ debug logs can be enabled in runtime by setting
+"persist.sys.bluetooth.debug" property to either literal "true" or any
+numeric value >0. For example:
+adb root
+adb shell setprop persist.sys.bluetooth.debug 1
+
+After changing property value Bluetooth needs to be restarted to apply changes.
+
+There is also a possibility to enable mgmt debug logs which also enables debugs
+as above. To enable it proceed in the same way as described above but use
+system properties called: persist.sys.bluetooth.mgmtdbg
+
+Note: Debugs are only available on NON USER build variants
+
+
+Customization
+-------------
+
+It is possible to customize BlueZ for Android through Android system properties.
+This may include enabling extra profiles or features inside HALs implementation
+These properties are read on Bluetooth stack startup only and require stack
+restart if changed. All customization properties names start with
+"persist.sys.bluetooth." or "ro.bluetooth." followed by specific HAL name e.g.
+"persist.sys.bluetooth.handsfree". If both are present "persist.sys.bluetooth."
+takes precedence. This allows for read only properties to be set during build
+leaving enough flexibility for developing or debugging purposes.
+This section list available customization options.
+
+Property Value Description
+-------------------------------------------
+mode bredr Enable BlueZ in BR/EDR mode
+ le Enable BlueZ in LE mode
+ <none> Enable BlueZ in default mode - enable BR/EDR/LE
+ if available.
+handsfree hfp Enable Handsfree Profile (HFP) with narrowband
+ speech only
+ hfp_wbs Enable Handsfree Profile (HFP) with narrowband
+ and wideband speech support
+ <none> Don't enable Handsfree Profile (HFP)
+vendor <any> Set vendor name in DIS. If not set fallback to
+ "ro.product.manufacturer".
+model <any> Set model name used as default adapter name.
+ If not set fallback to "ro.product.model".
+name <any> Set model number in DIS. If not set fallback to
+ "ro.product.name".
+serialno <any> Set serial number in DIS. If not set fallback to
+ "ro.serialno".
+systemid <uint64> Set system ID in DIS. Hex string encoded uint64.
+pnpid <any> PnP information used in DIS and DID profiles.
+ Required format: "Source:VID:PID:Version".
+ Source must be either "bluetooth" or "usb".
+ VID, PID and Version are uint16. Version is
+ optional.
+fwrev <any> Firmware revision in DIS. If not set fallback to
+ "ro.build.version.release".
+hwrew <any> Hardware revision in DIS. If not set fallback to
+ "ro.board.platform".
+
+
+Building and running on Linux
+-----------------------------
+
+It is possible to build and test BlueZ for Android daemon on Linux (eg. PC).
+Simply follow instructions available at README file in BlueZ top directory.
+Android daemon binary is located at android/bluetoothd. See next section on
+how to test Android daemon on Linux.
+
+
+Testing tool
+------------
+
+BT HAL test tools located in android/haltest is provided for HAL level testing
+of both Android daemon and HAL library. Start it with '-n' parameter and type
+'bluetooth init' in prompt to initialize HAL library. Running without parameter
+will make haltest try to initialize all services after start. On Android
+required bluetoothd service will be started automatically. On Linux it is
+required to start android/bluetoothd manually before init command timeout or
+use provided android/system-emulator, which takes care of launching daemon
+automatically on HAL library initialization. To deinitialize HAL library and
+stop daemon type 'bluetooth cleanup'. Type 'help' for more information. Tab
+completion is also supported.
+
+
+Implementation status
+=====================
+
+Summary of HALs implementation status.
+
+complete - implementation is feature complete and Android Framework is able
+ to use it normally
+partial - implementation is in progress and not all required features are
+ present, Android Framework is able to use some of features
+initial - only initial implementations is present, Android Framework is
+ able to initialize but most likely not able to use it
+not started - no implementation, Android Framework is not able to initialize it
+
+Profile ID HAL header 4.4 Status 5.0 status
+-------------------------------------------------------------
+core bluetooth.h complete partial
+a2dp bt_av.h complete complete
+gatt bt_gatt.h complete partial
+ bt_gatt_client.h complete partial
+ bt_gatt_server.h complete partial
+handsfree bt_hf.h complete complete
+hidhost bt_hh.h complete complete
+health bt_hl.h complete complete
+pan bt_pan.h complete complete
+avrcp bt_rc.h complete complete
+socket bt_sock.h complete partial
+handsfree_client bt_hf_client.h N/A complete
+map_client bt_mce.h N/A complete
+a2dp_sink bt_av.h N/A partial
+avrcp_ctrl bt_rc.h N/A partial
+
+
+Implementation shortcomings
+===========================
+
+It is possible that some of HAL functionality (although being marked as
+complete) is missing implementation due to reasons like feature feasibility or
+necessity for latest Android Framework. This sections provides list of such
+deficiencies. Note that HAL library is always expected to fully implement HAL
+API so missing implementation might happen only in daemon.
+
+
+HAL Bluetooth
+-------------
+
+methods:
+dut_mode_send never called from Android Framework
+le_test_mode never called from Android Framework
+
+callbacks:
+dut_mode_recv_cb empty JNI implementation
+le_test_mode_cb empty JNI implementation
+
+properties:
+BT_PROPERTY_SERVICE_RECORD not supported for adapter, for device this
+ property is returned as a response to
+ get_remote_service_record call
+
+BT_PROPERTY_REMOTE_VERSION_INFO information required by this property (LMP
+ information) are not accessible from mgmt
+ interface, also marking this property as
+ settable is probably a typo in HAL header
+
+HAL Socket
+----------
+
+Support only for BTSOCK_RFCOMM socket type.
+
+
+HAL AVRCP
+---------
+
+methods:
+list_player_app_attr_rsp never called from Android Framework
+list_player_app_value_rsp never called from Android Framework
+get_player_app_value_rsp never called from Android Framework
+get_player_app_attr_text_rsp never called from Android Framework
+get_player_app_value_text_rsp never called from Android Framework
+set_player_app_value_rsp never called from Android Framework
+
+callbacks:
+list_player_app_attr_cb NULL JNI implementation
+list_player_app_values_cb NULL JNI implementation
+get_player_app_value_cb NULL JNI implementation
+get_player_app_attrs_text_cb NULL JNI implementation
+get_player_app_values_text_cb NULL JNI implementation
+set_player_app_value_cb NULL JNI implementation
+
+
+HAL GATT
+--------
+
+methods:
+client->set_adv_data missing kernel support for vendor data
+client->connect is_direct parameter is ignored
+
+
+Audio SCO HAL
+=============
+
+When Bluetooth chip's audio is not wired directly to device audio, Audio SCO
+HAL is used to enable SCO support. It needs to be loaded by AudioFlinger
+following audio_policy.conf configuration. Example of configuration is shown
+below:
+
+...
+ sco {
+ outputs {
+ sco {
+ sampling_rates 8000|44100
+ channel_masks AUDIO_CHANNEL_OUT_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_ALL_SCO
+ }
+ }
+ inputs {
+ sco {
+ sampling_rates 8000|44100
+ channel_masks AUDIO_CHANNEL_IN_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET
+ }
+ }
+ }
+...
+
+Known Android issues
+====================
+
+It is possible that BlueZ is triggering bugs on Android Framework that could
+affect qualification or user experience. This section provides list of
+recommended Android fixes that are not part of latest AOSP release supported by
+BlueZ.
+
+For Android 5.1 Lollipop:
+https://android-review.googlesource.com/177314
+
+For Android 5.0 Lollipop:
+https://android-review.googlesource.com/99761
+https://android-review.googlesource.com/100297
+https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/132733
+https://android-review.googlesource.com/132763
+https://android-review.googlesource.com/177314
+
+For Android 4.4 KitKat:
+https://android-review.googlesource.com/82757
+https://android-review.googlesource.com/87670
+https://android-review.googlesource.com/88384
+https://android-review.googlesource.com/99761
+https://android-review.googlesource.com/99850
+https://android-review.googlesource.com/100297
+https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/177314
+
+Unimplemented Bluetooth features
+================================
+
+Some Bluetooth functionality require support from outside of BT stack
+eg. telephony stack. This sections describes profiles optional features not
+implemented due to lack of support in other Android subsystems or missing API
+in respective BT HALs.
+
+Profile Feature Comments
+--------------------------------------------------------
+HFP Attach a phone number to AT+BINP=1
+ a voice tag
+HFP Enhanced Call Control AT+CHLD={1x,2x}
+HFP Explicit Call Transfer AT+CHLD=4
+HFP Response and Hold AT+BTRH, +BTRH
+HFP In-band Ring Tone +BSIR
+AVRCP Player Settings HAL API present but not used
+AVRCP Browsing No HAL API
+GATT Read multiple characteristics No HAL API
+
+
+Reporting Bugs
+==============
+
+Bugs should be reported at https://01.org/jira/browse/BA. When reporting
+a bug please attach logs from logcat (logcat -v time) and HCI trace. Daemon
+debug logs should be enabled. When reporting daemon crash please run it under
+valgrind if possible. For details on how to enabled debug logs and valgrind see
+"Enabling BlueZ debugs" section.
diff --git a/repo/android/a2dp-sink.c b/repo/android/a2dp-sink.c
new file mode 100644
index 0000000..7c1e1a0
--- /dev/null
+++ b/repo/android/a2dp-sink.c
@@ -0,0 +1,84 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+#include "a2dp-sink.h"
+
+static struct ipc *hal_ipc = NULL;
+
+static void bt_a2dp_sink_connect(const void *buf, uint16_t len)
+{
+ /* TODO */
+
+ DBG("");
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_CONNECT,
+ HAL_STATUS_UNSUPPORTED);
+}
+
+static void bt_a2dp_sink_disconnect(const void *buf, uint16_t len)
+{
+ /* TODO */
+
+ DBG("");
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_DISCONNECT,
+ HAL_STATUS_UNSUPPORTED);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+ /* HAL_OP_A2DP_CONNECT */
+ { bt_a2dp_sink_connect, false, sizeof(struct hal_cmd_a2dp_connect) },
+ /* HAL_OP_A2DP_DISCONNECT */
+ { bt_a2dp_sink_disconnect, false,
+ sizeof(struct hal_cmd_a2dp_disconnect) },
+};
+
+bool bt_a2dp_sink_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
+{
+ DBG("");
+
+ hal_ipc = ipc;
+ ipc_register(hal_ipc, HAL_SERVICE_ID_A2DP_SINK, cmd_handlers,
+ G_N_ELEMENTS(cmd_handlers));
+
+ return true;
+}
+
+void bt_a2dp_sink_unregister(void)
+{
+ DBG("");
+
+ ipc_unregister(hal_ipc, HAL_SERVICE_ID_A2DP_SINK);
+ hal_ipc = NULL;
+}
diff --git a/repo/android/a2dp-sink.h b/repo/android/a2dp-sink.h
new file mode 100644
index 0000000..d2c5ff4
--- /dev/null
+++ b/repo/android/a2dp-sink.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+bool bt_a2dp_sink_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
+void bt_a2dp_sink_unregister(void);
diff --git a/repo/android/a2dp.c b/repo/android/a2dp.c
new file mode 100644
index 0000000..f219042
--- /dev/null
+++ b/repo/android/a2dp.c
@@ -0,0 +1,1774 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "btio/btio.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "profiles/audio/a2dp-codecs.h"
+#include "src/shared/queue.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc-common.h"
+#include "ipc.h"
+#include "a2dp.h"
+#include "utils.h"
+#include "bluetooth.h"
+#include "avdtp.h"
+#include "avrcp.h"
+#include "audio-msg.h"
+
+#define SVC_HINT_CAPTURING 0x08
+#define IDLE_TIMEOUT 1
+#define AUDIO_RETRY_TIMEOUT 2
+
+static GIOChannel *server = NULL;
+static GSList *devices = NULL;
+static GSList *endpoints = NULL;
+static GSList *setups = NULL;
+static bdaddr_t adapter_addr;
+static uint32_t record_id = 0;
+static guint audio_retry_id = 0;
+static bool audio_retrying = false;
+
+static struct ipc *hal_ipc = NULL;
+static struct ipc *audio_ipc = NULL;
+
+static struct queue *lseps = NULL;
+
+struct a2dp_preset {
+ void *data;
+ int8_t len;
+};
+
+struct a2dp_endpoint {
+ uint8_t id;
+ uint8_t codec;
+ struct avdtp_local_sep *sep;
+ struct a2dp_preset *caps;
+ GSList *presets;
+};
+
+struct a2dp_device {
+ bdaddr_t dst;
+ uint8_t state;
+ GIOChannel *io;
+ struct avdtp *session;
+ guint idle_id;
+};
+
+struct a2dp_setup {
+ struct a2dp_device *dev;
+ struct a2dp_endpoint *endpoint;
+ struct a2dp_preset *preset;
+ struct avdtp_stream *stream;
+ uint8_t state;
+};
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+ const struct a2dp_device *dev = s;
+ const bdaddr_t *dst = user_data;
+
+ return bacmp(&dev->dst, dst);
+}
+
+static void preset_free(void *data)
+{
+ struct a2dp_preset *preset = data;
+
+ g_free(preset->data);
+ g_free(preset);
+}
+
+static void unregister_endpoint(void *data)
+{
+ struct a2dp_endpoint *endpoint = data;
+
+ if (endpoint->sep)
+ avdtp_unregister_sep(lseps, endpoint->sep);
+
+ if (endpoint->caps)
+ preset_free(endpoint->caps);
+
+ g_slist_free_full(endpoint->presets, preset_free);
+
+ g_free(endpoint);
+}
+
+static void setup_free(void *data)
+{
+ struct a2dp_setup *setup = data;
+
+ if (!g_slist_find(setup->endpoint->presets, setup->preset))
+ preset_free(setup->preset);
+
+ g_free(setup);
+}
+
+static void setup_remove(struct a2dp_setup *setup)
+{
+ setups = g_slist_remove(setups, setup);
+ setup_free(setup);
+}
+
+static void setup_remove_all_by_dev(struct a2dp_device *dev)
+{
+ GSList *l = setups;
+
+ while (l) {
+ struct a2dp_setup *setup = l->data;
+ GSList *next = g_slist_next(l);
+
+ if (setup->dev == dev)
+ setup_remove(setup);
+
+ l = next;
+ }
+}
+
+static void a2dp_device_free(void *data)
+{
+ struct a2dp_device *dev = data;
+
+ if (dev->idle_id > 0)
+ g_source_remove(dev->idle_id);
+
+ if (dev->session)
+ avdtp_unref(dev->session);
+
+ if (dev->io) {
+ g_io_channel_shutdown(dev->io, FALSE, NULL);
+ g_io_channel_unref(dev->io);
+ }
+
+ setup_remove_all_by_dev(dev);
+
+ g_free(dev);
+}
+
+static void a2dp_device_remove(struct a2dp_device *dev)
+{
+ devices = g_slist_remove(devices, dev);
+ a2dp_device_free(dev);
+}
+
+static struct a2dp_device *a2dp_device_new(const bdaddr_t *dst)
+{
+ struct a2dp_device *dev;
+
+ dev = g_new0(struct a2dp_device, 1);
+ bacpy(&dev->dst, dst);
+ devices = g_slist_prepend(devices, dev);
+
+ return dev;
+}
+
+static bool a2dp_device_connect(struct a2dp_device *dev, BtIOConnect cb)
+{
+ GError *err = NULL;
+
+ dev->io = bt_io_connect(cb, dev, NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_DEST_BDADDR, &dev->dst,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
+ return true;
+}
+
+static void bt_a2dp_notify_state(struct a2dp_device *dev, uint8_t state)
+{
+ struct hal_ev_a2dp_conn_state ev;
+ char address[18];
+
+ if (dev->state == state)
+ return;
+
+ dev->state = state;
+
+ ba2str(&dev->dst, address);
+ DBG("device %s state %u", address, state);
+
+ bdaddr2android(&dev->dst, ev.bdaddr);
+ ev.state = state;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_EV_A2DP_CONN_STATE,
+ sizeof(ev), &ev);
+
+ if (state != HAL_A2DP_STATE_DISCONNECTED)
+ return;
+
+ bt_avrcp_disconnect(&dev->dst);
+
+ a2dp_device_remove(dev);
+}
+
+static void bt_audio_notify_state(struct a2dp_setup *setup, uint8_t state)
+{
+ struct hal_ev_a2dp_audio_state ev;
+ char address[18];
+
+ if (setup->state == state)
+ return;
+
+ setup->state = state;
+
+ ba2str(&setup->dev->dst, address);
+ DBG("device %s state %u", address, state);
+
+ bdaddr2android(&setup->dev->dst, ev.bdaddr);
+ ev.state = state;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_EV_A2DP_AUDIO_STATE,
+ sizeof(ev), &ev);
+}
+
+static void disconnect_cb(void *user_data)
+{
+ struct a2dp_device *dev = user_data;
+
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+}
+
+static int sbc_check_config(void *caps, uint8_t caps_len, void *conf,
+ uint8_t conf_len)
+{
+ a2dp_sbc_t *cap, *config;
+
+ if (conf_len != caps_len || conf_len != sizeof(a2dp_sbc_t)) {
+ error("SBC: Invalid configuration size (%u)", conf_len);
+ return -EINVAL;
+ }
+
+ cap = caps;
+ config = conf;
+
+ if (!(cap->frequency & config->frequency)) {
+ error("SBC: Unsupported frequency (%u) by endpoint",
+ config->frequency);
+ return -EINVAL;
+ }
+
+ if (!(cap->channel_mode & config->channel_mode)) {
+ error("SBC: Unsupported channel mode (%u) by endpoint",
+ config->channel_mode);
+ return -EINVAL;
+ }
+
+ if (!(cap->block_length & config->block_length)) {
+ error("SBC: Unsupported block length (%u) by endpoint",
+ config->block_length);
+ return -EINVAL;
+ }
+
+ if (!(cap->allocation_method & config->allocation_method)) {
+ error("SBC: Unsupported allocation method (%u) by endpoint",
+ config->block_length);
+ return -EINVAL;
+ }
+
+ if (config->max_bitpool < cap->min_bitpool) {
+ error("SBC: Invalid maximun bitpool (%u < %u)",
+ config->max_bitpool, cap->min_bitpool);
+ return -EINVAL;
+ }
+
+ if (config->min_bitpool > cap->max_bitpool) {
+ error("SBC: Invalid minimun bitpool (%u > %u)",
+ config->min_bitpool, cap->min_bitpool);
+ return -EINVAL;
+ }
+
+ if (config->max_bitpool > cap->max_bitpool)
+ return -ERANGE;
+
+ if (config->min_bitpool < cap->min_bitpool)
+ return -ERANGE;
+
+ return 0;
+}
+
+static int aac_check_config(void *caps, uint8_t caps_len, void *conf,
+ uint8_t conf_len)
+{
+ a2dp_aac_t *cap, *config;
+
+ if (conf_len != caps_len || conf_len != sizeof(a2dp_aac_t)) {
+ error("AAC: Invalid configuration size (%u)", conf_len);
+ return -EINVAL;
+ }
+
+ cap = caps;
+ config = conf;
+
+ if (!(cap->object_type & config->object_type)) {
+ error("AAC: Unsupported object type (%u) by endpoint",
+ config->object_type);
+ return -EINVAL;
+ }
+
+ if (!(AAC_GET_FREQUENCY(*cap) & AAC_GET_FREQUENCY(*config))) {
+ error("AAC: Unsupported frequency (%u) by endpoint",
+ AAC_GET_FREQUENCY(*config));
+ return -EINVAL;
+ }
+
+ if (!(cap->channels & config->channels)) {
+ error("AAC: Unsupported channels (%u) by endpoint",
+ config->channels);
+ return -EINVAL;
+ }
+
+ /* VBR support in SNK is mandatory but let's make sure we don't try to
+ * have VBR on remote which for some reason does not support it
+ */
+ if (!cap->vbr && config->vbr) {
+ error("AAC: Unsupported VBR (%u) by endpoint",
+ config->vbr);
+ return -EINVAL;
+ }
+
+ if (AAC_GET_BITRATE(*cap) < AAC_GET_BITRATE(*config))
+ return -ERANGE;
+
+ return 0;
+}
+
+static int aptx_check_config(void *caps, uint8_t caps_len, void *conf,
+ uint8_t conf_len)
+{
+ a2dp_aptx_t *cap, *config;
+
+ if (conf_len != caps_len || conf_len != sizeof(a2dp_aptx_t)) {
+ error("APTX: Invalid configuration size (%u)", conf_len);
+ return -EINVAL;
+ }
+
+ cap = caps;
+ config = conf;
+
+ if (!(cap->frequency & config->frequency)) {
+ error("APTX: Unsupported frequenct (%u) by endpoint",
+ config->frequency);
+ return -EINVAL;
+ }
+
+ if (!(cap->channel_mode & config->channel_mode)) {
+ error("APTX: Unsupported channel mode (%u) by endpoint",
+ config->channel_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int check_capabilities(struct a2dp_preset *preset,
+ struct avdtp_media_codec_capability *codec,
+ uint8_t codec_len)
+{
+ a2dp_vendor_codec_t *vndcodec;
+
+ /* Codec specific */
+ switch (codec->media_codec_type) {
+ case A2DP_CODEC_SBC:
+ return sbc_check_config(codec->data, codec_len, preset->data,
+ preset->len);
+ case A2DP_CODEC_MPEG24:
+ return aac_check_config(codec->data, codec_len, preset->data,
+ preset->len);
+ case A2DP_CODEC_VENDOR:
+ vndcodec = (void *) codec->data;
+ if (btohl(vndcodec->vendor_id) == APTX_VENDOR_ID &&
+ btohs(vndcodec->codec_id) == APTX_CODEC_ID)
+ return aptx_check_config(codec->data, codec_len,
+ preset->data, preset->len);
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct a2dp_preset *sbc_select_range(void *caps, uint8_t caps_len,
+ void *conf, uint8_t conf_len)
+{
+ struct a2dp_preset *p;
+ a2dp_sbc_t *cap, *config;
+
+ cap = caps;
+ config = conf;
+
+ config->min_bitpool = MAX(config->min_bitpool, cap->min_bitpool);
+ config->max_bitpool = MIN(config->max_bitpool, cap->max_bitpool);
+
+ p = g_new0(struct a2dp_preset, 1);
+ p->len = conf_len;
+ p->data = g_memdup(conf, p->len);
+
+ return p;
+}
+
+static struct a2dp_preset *aac_select_range(void *caps, uint8_t caps_len,
+ void *conf, uint8_t conf_len)
+{
+ struct a2dp_preset *p;
+ a2dp_aac_t *cap, *config;
+ uint32_t bitrate;
+
+ cap = caps;
+ config = conf;
+
+ bitrate = MIN(AAC_GET_BITRATE(*cap), AAC_GET_BITRATE(*config));
+ AAC_SET_BITRATE(*config, bitrate);
+
+ p = g_new0(struct a2dp_preset, 1);
+ p->len = conf_len;
+ p->data = g_memdup(conf, p->len);
+
+ return p;
+}
+
+static struct a2dp_preset *select_preset_range(struct a2dp_preset *preset,
+ struct avdtp_media_codec_capability *codec,
+ uint8_t codec_len)
+{
+ /* Codec specific */
+ switch (codec->media_codec_type) {
+ case A2DP_CODEC_SBC:
+ return sbc_select_range(codec->data, codec_len, preset->data,
+ preset->len);
+ case A2DP_CODEC_MPEG24:
+ return aac_select_range(codec->data, codec_len, preset->data,
+ preset->len);
+ default:
+ return NULL;
+ }
+}
+
+static struct a2dp_preset *select_preset(struct a2dp_endpoint *endpoint,
+ struct avdtp_remote_sep *rsep)
+{
+ struct avdtp_service_capability *service;
+ struct avdtp_media_codec_capability *codec;
+ GSList *l;
+ uint8_t codec_len;
+
+ service = avdtp_get_codec(rsep);
+ codec = (struct avdtp_media_codec_capability *) service->data;
+ codec_len = service->length - sizeof(*codec);
+
+ for (l = endpoint->presets; l; l = g_slist_next(l)) {
+ struct a2dp_preset *preset = l->data;
+ int err;
+
+ err = check_capabilities(preset, codec, codec_len);
+ if (err == 0)
+ return preset;
+
+ if (err == -ERANGE)
+ return select_preset_range(preset, codec, codec_len);
+ }
+
+ return NULL;
+}
+
+static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
+ struct a2dp_preset *preset, struct avdtp_stream *stream)
+{
+ struct a2dp_setup *setup;
+
+ setup = g_new0(struct a2dp_setup, 1);
+ setup->dev = dev;
+ setup->endpoint = endpoint;
+ setup->preset = preset;
+ setup->stream = stream;
+ setups = g_slist_append(setups, setup);
+
+ if (dev->idle_id > 0) {
+ g_source_remove(dev->idle_id);
+ dev->idle_id = 0;
+ }
+}
+
+static int select_configuration(struct a2dp_device *dev,
+ struct a2dp_endpoint *endpoint,
+ struct avdtp_remote_sep *rsep)
+{
+ struct a2dp_preset *preset;
+ struct avdtp_stream *stream;
+ struct avdtp_service_capability *service;
+ struct avdtp_media_codec_capability *codec;
+ GSList *caps;
+ int err;
+
+ preset = select_preset(endpoint, rsep);
+ if (!preset) {
+ error("Unable to select codec preset");
+ return -EINVAL;
+ }
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+ caps = g_slist_append(NULL, service);
+
+ codec = g_malloc0(sizeof(*codec) + preset->len);
+ codec->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ codec->media_codec_type = endpoint->codec;
+ memcpy(codec->data, preset->data, preset->len);
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec,
+ sizeof(*codec) + preset->len);
+ caps = g_slist_append(caps, service);
+
+ g_free(codec);
+
+ err = avdtp_set_configuration(dev->session, rsep, endpoint->sep, caps,
+ &stream);
+ g_slist_free_full(caps, g_free);
+ if (err < 0) {
+ error("avdtp_set_configuration: %s", strerror(-err));
+ return err;
+ }
+
+ setup_add(dev, endpoint, preset, stream);
+
+ return 0;
+}
+
+static void discover_cb(struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data)
+{
+ struct a2dp_device *dev = user_data;
+ struct a2dp_endpoint *endpoint = NULL;
+ struct avdtp_remote_sep *rsep = NULL;
+ GSList *l;
+
+ for (l = endpoints; l; l = g_slist_next(l)) {
+ endpoint = l->data;
+
+ rsep = avdtp_find_remote_sep(session, endpoint->sep);
+ if (rsep)
+ break;
+ }
+
+ if (!rsep) {
+ error("Unable to find matching endpoint");
+ goto failed;
+ }
+
+ if (select_configuration(dev, endpoint, rsep) < 0)
+ goto failed;
+
+ return;
+
+failed:
+ avdtp_shutdown(session);
+}
+
+static gboolean idle_timeout(gpointer user_data)
+{
+ struct a2dp_device *dev = user_data;
+ int err;
+
+ dev->idle_id = 0;
+
+ err = avdtp_discover(dev->session, discover_cb, dev);
+ if (err == 0)
+ return FALSE;
+
+ error("avdtp_discover: %s", strerror(-err));
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+
+static void signaling_connect_cb(GIOChannel *chan, GError *err,
+ gpointer user_data)
+{
+ struct a2dp_device *dev = user_data;
+ struct avdtp *session;
+ uint16_t imtu, omtu;
+ GError *gerr = NULL;
+ int fd;
+
+ if (err) {
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+ error("%s", err->message);
+ return;
+ }
+
+ bt_io_get(chan, &gerr,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ goto failed;
+ }
+
+ fd = g_io_channel_unix_get_fd(chan);
+
+ /* FIXME: Add proper version */
+ session = avdtp_new(fd, imtu, omtu, 0x0100, lseps);
+ if (!session)
+ goto failed;
+
+ dev->session = session;
+
+ avdtp_add_disconnect_cb(dev->session, disconnect_cb, dev);
+
+ /* Proceed to stream setup if initiator */
+ if (dev->io) {
+ int perr;
+
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+
+ perr = avdtp_discover(dev->session, discover_cb, dev);
+ if (perr < 0) {
+ error("avdtp_discover: %s", strerror(-perr));
+ goto failed;
+ }
+ bt_avrcp_connect(&dev->dst);
+ } else /* Init idle timeout to discover */
+ dev->idle_id = g_timeout_add_seconds(IDLE_TIMEOUT, idle_timeout,
+ dev);
+
+ return;
+
+failed:
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+}
+
+static void bt_a2dp_connect(const void *buf, uint16_t len)
+{
+ const struct hal_cmd_a2dp_connect *cmd = buf;
+ struct a2dp_device *dev;
+ uint8_t status;
+ char addr[18];
+ bdaddr_t dst;
+ GSList *l;
+
+ DBG("");
+
+ android2bdaddr(&cmd->bdaddr, &dst);
+
+ l = g_slist_find_custom(devices, &dst, device_cmp);
+ if (l) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ dev = a2dp_device_new(&dst);
+ if (!a2dp_device_connect(dev, signaling_connect_cb)) {
+ a2dp_device_remove(dev);
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ ba2str(&dev->dst, addr);
+ DBG("connecting to %s", addr);
+
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_CONNECT, status);
+}
+
+static void bt_a2dp_disconnect(const void *buf, uint16_t len)
+{
+ const struct hal_cmd_a2dp_connect *cmd = buf;
+ uint8_t status;
+ struct a2dp_device *dev;
+ GSList *l;
+ bdaddr_t dst;
+
+ DBG("");
+
+ android2bdaddr(&cmd->bdaddr, &dst);
+
+ l = g_slist_find_custom(devices, &dst, device_cmp);
+ if (!l) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ dev = l->data;
+ status = HAL_STATUS_SUCCESS;
+
+ if (dev->io) {
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+ goto failed;
+ }
+
+ /* Wait AVDTP session to shutdown */
+ avdtp_shutdown(dev->session);
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTING);
+
+failed:
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_DISCONNECT,
+ status);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+ /* HAL_OP_A2DP_CONNECT */
+ { bt_a2dp_connect, false, sizeof(struct hal_cmd_a2dp_connect) },
+ /* HAL_OP_A2DP_DISCONNECT */
+ { bt_a2dp_disconnect, false, sizeof(struct hal_cmd_a2dp_disconnect) },
+};
+
+static struct a2dp_setup *find_setup_by_device(struct a2dp_device *dev)
+{
+ GSList *l;
+
+ for (l = setups; l; l = g_slist_next(l)) {
+ struct a2dp_setup *setup = l->data;
+
+ if (setup->dev == dev)
+ return setup;
+ }
+
+ return NULL;
+}
+
+static void transport_connect_cb(GIOChannel *chan, GError *err,
+ gpointer user_data)
+{
+ struct a2dp_device *dev = user_data;
+ struct a2dp_setup *setup;
+ uint16_t imtu, omtu;
+ GError *gerr = NULL;
+ int fd;
+
+ if (err) {
+ error("%s", err->message);
+ return;
+ }
+
+ setup = find_setup_by_device(dev);
+ if (!setup) {
+ error("Unable to find stream setup");
+ return;
+ }
+
+ bt_io_get(chan, &gerr,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ fd = g_io_channel_unix_get_fd(chan);
+
+ if (!avdtp_stream_set_transport(setup->stream, fd, imtu, omtu)) {
+ error("avdtp_stream_set_transport: failed");
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, FALSE);
+
+ if (dev->io) {
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+ }
+
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTED);
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct a2dp_device *dev;
+ bdaddr_t dst;
+ char address[18];
+ GError *gerr = NULL;
+ GSList *l;
+
+ if (err) {
+ error("%s", err->message);
+ return;
+ }
+
+ bt_io_get(chan, &gerr,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ return;
+ }
+
+ ba2str(&dst, address);
+ DBG("Incoming connection from %s", address);
+
+ l = g_slist_find_custom(devices, &dst, device_cmp);
+ if (l) {
+ transport_connect_cb(chan, err, l->data);
+ return;
+ }
+
+ dev = a2dp_device_new(&dst);
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTING);
+ signaling_connect_cb(chan, err, dev);
+}
+
+static sdp_record_t *a2dp_record(void)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = AVDTP_UUID;
+ uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &a2dp_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
+ profile[0].version = a2dp_ver;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
+ proto[1] = sdp_list_append(NULL, &avdtp_uuid);
+ version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(record, "Audio Source", NULL, NULL);
+
+ sdp_data_free(psm);
+ sdp_data_free(version);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(pfseq, NULL);
+ sdp_list_free(aproto, NULL);
+ sdp_list_free(root, NULL);
+ sdp_list_free(svclass_id, NULL);
+
+ return record;
+}
+
+static gboolean sep_getcap_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_preset *cap = endpoint->caps;
+ struct avdtp_service_capability *service;
+ struct avdtp_media_codec_capability *codec;
+
+ *caps = NULL;
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+ *caps = g_slist_append(*caps, service);
+
+ codec = g_malloc0(sizeof(*codec) + cap->len);
+ codec->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ codec->media_codec_type = endpoint->codec;
+ memcpy(codec->data, cap->data, cap->len);
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec,
+ sizeof(*codec) + cap->len);
+ *caps = g_slist_append(*caps, service);
+ g_free(codec);
+
+ return TRUE;
+}
+
+static int check_config(struct a2dp_endpoint *endpoint,
+ struct a2dp_preset *config)
+{
+ GSList *l;
+ struct a2dp_preset *caps;
+
+ for (l = endpoint->presets; l; l = g_slist_next(l)) {
+ struct a2dp_preset *preset = l->data;
+
+ if (preset->len != config->len)
+ continue;
+
+ if (memcmp(preset->data, config->data, preset->len) == 0)
+ return 0;
+ }
+
+ caps = endpoint->caps;
+
+ /* Codec specific */
+ switch (endpoint->codec) {
+ case A2DP_CODEC_SBC:
+ return sbc_check_config(caps->data, caps->len, config->data,
+ config->len);
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct a2dp_device *find_device_by_session(struct avdtp *session)
+{
+ GSList *l;
+
+ for (l = devices; l; l = g_slist_next(l)) {
+ struct a2dp_device *dev = l->data;
+
+ if (dev->session == session)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static struct a2dp_setup *find_setup(uint8_t id)
+{
+ GSList *l;
+
+ for (l = setups; l; l = g_slist_next(l)) {
+ struct a2dp_setup *setup = l->data;
+
+ if (setup->endpoint->id == id)
+ return setup;
+ }
+
+ return NULL;
+}
+
+static void setup_remove_by_id(uint8_t id)
+{
+ struct a2dp_setup *setup;
+
+ setup = find_setup(id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u", id);
+ return;
+ }
+
+ setup_remove(setup);
+}
+
+static gboolean sep_setconf_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ GSList *caps,
+ avdtp_set_configuration_cb cb,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_device *dev;
+ struct a2dp_preset *preset = NULL;
+
+ DBG("");
+
+ dev = find_device_by_session(session);
+ if (!dev) {
+ error("Unable to find device for session %p", session);
+ return FALSE;
+ }
+
+ for (; caps != NULL; caps = g_slist_next(caps)) {
+ struct avdtp_service_capability *cap = caps->data;
+ struct avdtp_media_codec_capability *codec;
+
+ if (cap->category == AVDTP_DELAY_REPORTING)
+ return FALSE;
+
+ if (cap->category != AVDTP_MEDIA_CODEC)
+ continue;
+
+ codec = (struct avdtp_media_codec_capability *) cap->data;
+
+ if (codec->media_codec_type != endpoint->codec)
+ return FALSE;
+
+ preset = g_new0(struct a2dp_preset, 1);
+ preset->len = cap->length - sizeof(*codec);
+ preset->data = g_memdup(codec->data, preset->len);
+
+ if (check_config(endpoint, preset) < 0) {
+ preset_free(preset);
+ return FALSE;
+ }
+ }
+
+ if (!preset)
+ return FALSE;
+
+ setup_add(dev, endpoint, preset, stream);
+
+ cb(session, stream, NULL);
+
+ return TRUE;
+}
+
+static gboolean sep_open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u",
+ endpoint->id);
+ *err = AVDTP_SEP_NOT_IN_USE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean sep_close_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u",
+ endpoint->id);
+ *err = AVDTP_SEP_NOT_IN_USE;
+ return FALSE;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+ setup_remove(setup);
+
+ return TRUE;
+}
+
+static gboolean sep_start_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u",
+ endpoint->id);
+ *err = AVDTP_SEP_NOT_IN_USE;
+ return FALSE;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STARTED);
+
+ return TRUE;
+}
+
+static gboolean sep_suspend_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u",
+ endpoint->id);
+ *err = AVDTP_SEP_NOT_IN_USE;
+ return FALSE;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_SUSPEND);
+
+ return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+ .get_capability = sep_getcap_ind,
+ .set_configuration = sep_setconf_ind,
+ .open = sep_open_ind,
+ .close = sep_close_ind,
+ .start = sep_start_ind,
+ .suspend = sep_suspend_ind,
+};
+
+static void sep_setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+ int ret;
+
+ DBG("");
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for endpoint %u",
+ endpoint->id);
+ return;
+ }
+
+ if (err)
+ goto failed;
+
+ ret = avdtp_open(session, stream);
+ if (ret < 0) {
+ error("avdtp_open: %s", strerror(-ret));
+ goto failed;
+ }
+
+ return;
+
+failed:
+ setup_remove(setup);
+}
+
+static void sep_open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_device *dev;
+
+ DBG("");
+
+ if (err)
+ goto failed;
+
+ dev = find_device_by_session(session);
+ if (!dev) {
+ error("Unable to find device for session");
+ goto failed;
+ }
+
+ a2dp_device_connect(dev, transport_connect_cb);
+
+ return;
+
+failed:
+ setup_remove_by_id(endpoint->id);
+}
+
+static void sep_start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ if (err) {
+ setup_remove_by_id(endpoint->id);
+ return;
+ }
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for %u endpoint",
+ endpoint->id);
+ return;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STARTED);
+}
+
+static void sep_suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ if (err) {
+ setup_remove_by_id(endpoint->id);
+ return;
+ }
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for %u endpoint",
+ endpoint->id);
+ return;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+}
+
+static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
+
+ DBG("");
+
+ if (err)
+ return;
+
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for %u endpoint",
+ endpoint->id);
+ return;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+ setup_remove(setup);
+}
+
+static void sep_abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+
+ DBG("");
+
+ if (err)
+ return;
+
+ setup_remove_by_id(endpoint->id);
+}
+
+static struct avdtp_sep_cfm sep_cfm = {
+ .set_configuration = sep_setconf_cfm,
+ .open = sep_open_cfm,
+ .start = sep_start_cfm,
+ .suspend = sep_suspend_cfm,
+ .close = sep_close_cfm,
+ .abort = sep_abort_cfm,
+};
+
+static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
+ GSList *presets)
+{
+ struct a2dp_endpoint *endpoint;
+
+ /* FIXME: Add proper check for uuid */
+
+ endpoint = g_new0(struct a2dp_endpoint, 1);
+ endpoint->id = g_slist_length(endpoints) + 1;
+ endpoint->codec = codec;
+ endpoint->sep = avdtp_register_sep(lseps, AVDTP_SEP_TYPE_SOURCE,
+ AVDTP_MEDIA_TYPE_AUDIO,
+ codec, FALSE, &sep_ind,
+ &sep_cfm, endpoint);
+ endpoint->caps = presets->data;
+ endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
+
+ if (endpoint->codec == A2DP_CODEC_VENDOR) {
+ a2dp_vendor_codec_t *vndcodec = (void *) endpoint->caps->data;
+
+ avdtp_sep_set_vendor_codec(endpoint->sep,
+ btohl(vndcodec->vendor_id),
+ btohs(vndcodec->codec_id));
+ }
+
+ endpoints = g_slist_append(endpoints, endpoint);
+
+ return endpoint->id;
+}
+
+static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
+ uint16_t len)
+{
+ GSList *l = NULL;
+ uint8_t i;
+
+ for (i = 0; count > i; i++) {
+ const uint8_t *ptr = (const uint8_t *) p;
+ struct a2dp_preset *preset;
+
+ if (len < sizeof(struct audio_preset)) {
+ DBG("Invalid preset index %u", i);
+ g_slist_free_full(l, preset_free);
+ return NULL;
+ }
+
+ len -= sizeof(struct audio_preset);
+ if (len == 0 || len < p->len) {
+ DBG("Invalid preset size of %u for index %u", len, i);
+ g_slist_free_full(l, preset_free);
+ return NULL;
+ }
+
+ preset = g_new0(struct a2dp_preset, 1);
+ preset->len = p->len;
+ preset->data = g_memdup(p->data, preset->len);
+ l = g_slist_append(l, preset);
+
+ len -= preset->len;
+ ptr += sizeof(*p) + preset->len;
+ p = (const struct audio_preset *) ptr;
+ }
+
+ return l;
+}
+
+static void bt_audio_open(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_open *cmd = buf;
+ struct audio_rsp_open rsp;
+ GSList *presets;
+
+ DBG("");
+
+ audio_retrying = false;
+
+ if (cmd->presets == 0) {
+ error("No audio presets found");
+ goto failed;
+ }
+
+ presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
+ if (!presets) {
+ error("No audio presets found");
+ goto failed;
+ }
+
+ rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
+ if (rsp.id == 0) {
+ g_slist_free_full(presets, preset_free);
+ error("Unable to register endpoint");
+ goto failed;
+ }
+
+ g_slist_free(presets);
+
+ ipc_send_rsp_full(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN,
+ sizeof(rsp), &rsp, -1);
+
+ return;
+
+failed:
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN,
+ AUDIO_STATUS_FAILED);
+}
+
+static struct a2dp_endpoint *find_endpoint(uint8_t id)
+{
+ GSList *l;
+
+ for (l = endpoints; l; l = g_slist_next(l)) {
+ struct a2dp_endpoint *endpoint = l->data;
+
+ if (endpoint->id == id)
+ return endpoint;
+ }
+
+ return NULL;
+}
+
+static void bt_audio_close(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_close *cmd = buf;
+ struct a2dp_endpoint *endpoint;
+
+ DBG("");
+
+ endpoint = find_endpoint(cmd->id);
+ if (!endpoint) {
+ error("Unable to find endpoint %u", cmd->id);
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE,
+ AUDIO_STATUS_FAILED);
+ return;
+ }
+
+ endpoints = g_slist_remove(endpoints, endpoint);
+ unregister_endpoint(endpoint);
+
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE,
+ AUDIO_STATUS_SUCCESS);
+}
+
+static void bt_stream_open(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_open_stream *cmd = buf;
+ struct audio_rsp_open_stream *rsp;
+ struct a2dp_setup *setup;
+ int fd;
+ uint16_t omtu;
+
+ DBG("");
+
+ if (cmd->id)
+ setup = find_setup(cmd->id);
+ else
+ setup = setups ? setups->data : NULL;
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+ AUDIO_STATUS_FAILED);
+ return;
+ }
+
+ if (!avdtp_stream_get_transport(setup->stream, &fd, NULL, &omtu,
+ NULL)) {
+ error("avdtp_stream_get_transport: failed");
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+ AUDIO_STATUS_FAILED);
+ return;
+ }
+
+ len = sizeof(struct audio_rsp_open_stream) +
+ sizeof(struct audio_preset) + setup->preset->len;
+ rsp = g_malloc0(len);
+ rsp->id = setup->endpoint->id;
+ rsp->mtu = omtu;
+ rsp->preset->len = setup->preset->len;
+ memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
+
+ ipc_send_rsp_full(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
+ len, rsp, fd);
+
+ g_free(rsp);
+}
+
+static void bt_stream_close(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_close_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+
+ DBG("");
+
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ err = avdtp_close(setup->dev->session, setup->stream, FALSE);
+ if (err < 0) {
+ error("avdtp_close: %s", strerror(-err));
+ goto failed;
+ }
+
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE_STREAM,
+ AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_CLOSE_STREAM,
+ AUDIO_STATUS_FAILED);
+}
+
+static void bt_stream_resume(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_resume_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+
+ DBG("");
+
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ if (setup->state != HAL_AUDIO_STARTED) {
+ err = avdtp_start(setup->dev->session, setup->stream);
+ if (err < 0) {
+ error("avdtp_start: %s", strerror(-err));
+ goto failed;
+ }
+ }
+
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_RESUME_STREAM,
+ AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_RESUME_STREAM,
+ AUDIO_STATUS_FAILED);
+}
+
+static void bt_stream_suspend(const void *buf, uint16_t len)
+{
+ const struct audio_cmd_suspend_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+
+ DBG("");
+
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ err = avdtp_suspend(setup->dev->session, setup->stream);
+ if (err < 0) {
+ error("avdtp_suspend: %s", strerror(-err));
+ goto failed;
+ }
+
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_SUSPEND_STREAM,
+ AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
+ ipc_send_rsp(audio_ipc, AUDIO_SERVICE_ID, AUDIO_OP_SUSPEND_STREAM,
+ AUDIO_STATUS_FAILED);
+}
+
+static const struct ipc_handler audio_handlers[] = {
+ /* AUDIO_OP_OPEN */
+ { bt_audio_open, true, sizeof(struct audio_cmd_open) },
+ /* AUDIO_OP_CLOSE */
+ { bt_audio_close, false, sizeof(struct audio_cmd_close) },
+ /* AUDIO_OP_OPEN_STREAM */
+ { bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
+ /* AUDIO_OP_CLOSE_STREAM */
+ { bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
+ /* AUDIO_OP_RESUME_STREAM */
+ { bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
+ /* AUDIO_OP_SUSPEND_STREAM */
+ { bt_stream_suspend, false, sizeof(struct audio_cmd_suspend_stream) },
+};
+
+static void bt_audio_unregister(void)
+{
+ DBG("");
+
+ if (audio_retry_id > 0)
+ g_source_remove(audio_retry_id);
+
+ g_slist_free_full(endpoints, unregister_endpoint);
+ endpoints = NULL;
+
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
+ ipc_cleanup(audio_ipc);
+ audio_ipc = NULL;
+
+ queue_destroy(lseps, NULL);
+}
+
+static bool bt_audio_register(ipc_disconnect_cb disconnect)
+{
+ DBG("");
+
+ audio_ipc = ipc_init(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+ AUDIO_SERVICE_ID_MAX, false, disconnect, NULL);
+ if (!audio_ipc)
+ return false;
+
+ ipc_register(audio_ipc, AUDIO_SERVICE_ID, audio_handlers,
+ G_N_ELEMENTS(audio_handlers));
+
+ return true;
+}
+
+static gboolean audio_retry_register(void *data)
+{
+ ipc_disconnect_cb cb = data;
+
+ audio_retry_id = 0;
+ audio_retrying = true;
+
+ bt_audio_register(cb);
+
+ return FALSE;
+}
+
+static void audio_disconnected(void *data)
+{
+ GSList *l;
+ bool restart;
+
+ DBG("");
+
+ if (audio_retrying)
+ goto retry;
+
+ restart = endpoints != NULL ? true : false;
+
+ bt_audio_unregister();
+
+ for (l = devices; l; l = g_slist_next(l)) {
+ struct a2dp_device *dev = l->data;
+
+ avdtp_shutdown(dev->session);
+ }
+
+ if (!restart)
+ return;
+
+retry:
+ audio_retry_id = g_timeout_add_seconds(AUDIO_RETRY_TIMEOUT,
+ audio_retry_register,
+ audio_disconnected);
+}
+
+bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
+{
+ GError *err = NULL;
+ sdp_record_t *rec;
+
+ DBG("");
+
+ bacpy(&adapter_addr, addr);
+
+ lseps = queue_new();
+
+ server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_MASTER, true,
+ BT_IO_OPT_INVALID);
+ if (!server) {
+ error("Failed to listen on AVDTP channel: %s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
+ rec = a2dp_record();
+ if (!rec) {
+ error("Failed to allocate A2DP record");
+ goto fail;
+ }
+
+ if (bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
+ error("Failed to register A2DP record");
+ sdp_record_free(rec);
+ goto fail;
+ }
+ record_id = rec->handle;
+
+ hal_ipc = ipc;
+
+ ipc_register(hal_ipc, HAL_SERVICE_ID_A2DP, cmd_handlers,
+ G_N_ELEMENTS(cmd_handlers));
+
+ if (bt_audio_register(audio_disconnected))
+ return true;
+
+fail:
+ g_io_channel_shutdown(server, TRUE, NULL);
+ g_io_channel_unref(server);
+ server = NULL;
+ return false;
+}
+
+void bt_a2dp_unregister(void)
+{
+ DBG("");
+
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
+ g_slist_free_full(endpoints, unregister_endpoint);
+ endpoints = NULL;
+
+ g_slist_free_full(devices, a2dp_device_free);
+ devices = NULL;
+
+ ipc_unregister(hal_ipc, HAL_SERVICE_ID_A2DP);
+ hal_ipc = NULL;
+
+ bt_adapter_remove_record(record_id);
+ record_id = 0;
+
+ if (server) {
+ g_io_channel_shutdown(server, TRUE, NULL);
+ g_io_channel_unref(server);
+ server = NULL;
+ }
+
+ if (audio_ipc) {
+ ipc_unregister(audio_ipc, AUDIO_SERVICE_ID);
+ ipc_cleanup(audio_ipc);
+ audio_ipc = NULL;
+ }
+}
diff --git a/repo/android/a2dp.h b/repo/android/a2dp.h
new file mode 100644
index 0000000..8a70407
--- /dev/null
+++ b/repo/android/a2dp.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
+void bt_a2dp_unregister(void);
diff --git a/repo/android/audio-ipc-api.txt b/repo/android/audio-ipc-api.txt
new file mode 100644
index 0000000..f4a497d
--- /dev/null
+++ b/repo/android/audio-ipc-api.txt
@@ -0,0 +1,87 @@
+Bluetooth Audio Plugin
+======================
+
+The audio plugin happen to be in a different socket but all the rules for
+HAL socket apply here as well, the abstract socket name is
+"\0bluez_audio_socket" (tentative):
+
+ .---Audio---. .--Android--.
+ | Plugin | | Daemon |
+ | | Command | |
+ | | --------------------------> | |
+ | | | |
+ | | <-------------------------- | |
+ | | Response | |
+ | | | |
+ | | | |
+ | | | |
+ '-----------' '-----------'
+
+
+ Audio HAL Daemon
+ ----------------------------------------------------
+
+ call dev->open() --> command 0x01
+ return dev->open() <-- response 0x01
+
+ call dev->open_output_stream() --> command 0x03
+ return dev->open_output_stream() <-- response 0x03
+
+ call stream->write() --> command 0x05
+ return stream->write() <-- response 0x05
+
+ call stream->common.standby() --> command 0x06
+ return stream->common.standby() <-- response 0x06
+
+ call dev->close_output_stream() --> command 0x04
+ return dev->close_output_stream() <-- response 0x04
+
+ call dev->close() --> command 0x02
+ return dev->close() <-- response 0x02
+
+Audio Service (ID 0)
+====================
+
+ Opcode 0x00 - Error response
+
+ Response parameters: Status (1 octet)
+
+ Opcode 0x01 - Open Audio Endpoint commmand
+
+ Command parameters: Service UUID (16 octets)
+ Codec ID (1 octet)
+ Number of codec presets (1 octet)
+ Codec capabilities length (1 octet)
+ Codec capabilities (variable)
+ Codec preset # length (1 octet)
+ Codec preset # configuration (variable)
+ ...
+ Response parameters: Endpoint ID (1 octet)
+
+ Opcode 0x02 - Close Audio Endpoint command
+
+ Command parameters: Endpoint ID (1 octet)
+ Response parameters: <none>
+
+ Opcode 0x03 - Open Stream command
+
+ Command parameters: Endpoint ID (1 octet)
+ Response parameters: Outgoing MTU (2 octets)
+ Codec configuration length (1 octet)
+ Codec configuration (1 octet)
+ File descriptor (inline)
+
+ Opcode 0x04 - Close Stream command
+
+ Command parameters: Endpoint ID (1 octet)
+ Response parameters: <none>
+
+ Opcode 0x05 - Resume Stream command
+
+ Command parameters: Endpoint ID (1 octet)
+ Response parameters: <none>
+
+ Opcode 0x06 - Suspend Stream command
+
+ Command parameters: Endpoint ID (1 octet)
+ Response parameters: <none>
diff --git a/repo/android/audio-msg.h b/repo/android/audio-msg.h
new file mode 100644
index 0000000..7b9553b
--- /dev/null
+++ b/repo/android/audio-msg.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define BLUEZ_AUDIO_MTU 1024
+
+static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
+
+#define AUDIO_SERVICE_ID 0
+#define AUDIO_SERVICE_ID_MAX AUDIO_SERVICE_ID
+
+#define AUDIO_STATUS_SUCCESS IPC_STATUS_SUCCESS
+#define AUDIO_STATUS_FAILED 0x01
+
+#define AUDIO_OP_STATUS IPC_OP_STATUS
+
+#define AUDIO_OP_OPEN 0x01
+struct audio_preset {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_cmd_open {
+ uint8_t uuid[16];
+ uint8_t codec;
+ uint8_t presets;
+ struct audio_preset preset[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+ uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE 0x02
+struct audio_cmd_close {
+ uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_OPEN_STREAM 0x03
+struct audio_cmd_open_stream {
+ uint8_t id;
+} __attribute__((packed));
+
+struct audio_rsp_open_stream {
+ uint16_t id;
+ uint16_t mtu;
+ struct audio_preset preset[0];
+} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE_STREAM 0x04
+struct audio_cmd_close_stream {
+ uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_RESUME_STREAM 0x05
+struct audio_cmd_resume_stream {
+ uint8_t id;
+} __attribute__((packed));
+
+#define AUDIO_OP_SUSPEND_STREAM 0x06
+struct audio_cmd_suspend_stream {
+ uint8_t id;
+} __attribute__((packed));
diff --git a/repo/android/audio_utils/resampler.c b/repo/android/audio_utils/resampler.c
new file mode 100644
index 0000000..ce30375
--- /dev/null
+++ b/repo/android/audio_utils/resampler.c
@@ -0,0 +1,270 @@
+/*
+** Copyright 2011, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <speex/speex_resampler.h>
+
+#include "hal-log.h"
+
+struct resampler {
+ struct resampler_itfe itfe;
+ SpeexResamplerState *speex_resampler; // handle on speex resampler
+ struct resampler_buffer_provider *provider; // buffer provider installed by client
+ uint32_t in_sample_rate; // input sampling rate in Hz
+ uint32_t out_sample_rate; // output sampling rate in Hz
+ uint32_t channel_count; // number of channels (interleaved)
+ int16_t *in_buf; // input buffer
+ size_t in_buf_size; // input buffer size
+ size_t frames_in; // number of frames in input buffer
+ size_t frames_rq; // cached number of output frames
+ size_t frames_needed; // minimum number of input frames to produce
+ // frames_rq output frames
+ int32_t speex_delay_ns; // delay introduced by speex resampler in ns
+};
+
+
+//------------------------------------------------------------------------------
+// speex based resampler
+//------------------------------------------------------------------------------
+
+static void resampler_reset(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ rsmp->frames_in = 0;
+ rsmp->frames_rq = 0;
+
+ if (rsmp != NULL && rsmp->speex_resampler != NULL) {
+ speex_resampler_reset_mem(rsmp->speex_resampler);
+ }
+}
+
+static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
+ delay += rsmp->speex_delay_ns;
+
+ return delay;
+}
+
+// outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount
+// with the actual number of frames produced.
+static int resampler_resample_from_provider(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+ size_t framesRq;
+ size_t framesWr;
+ size_t inFrames;
+
+ if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider == NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ framesRq = *outFrameCount;
+ // update and cache the number of frames needed at the input sampling rate to produce
+ // the number of frames requested at the output sampling rate
+ if (framesRq != rsmp->frames_rq) {
+ rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
+ rsmp->frames_rq = framesRq;
+ }
+
+ framesWr = 0;
+ inFrames = 0;
+ while (framesWr < framesRq) {
+ size_t outFrames;
+ if (rsmp->frames_in < rsmp->frames_needed) {
+ struct resampler_buffer buf;
+ // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
+ // least the number of frames needed to produce the number of frames requested at
+ // the output sampling rate
+ if (rsmp->in_buf_size < rsmp->frames_needed) {
+ rsmp->in_buf_size = rsmp->frames_needed;
+ rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
+ rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
+ }
+ buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
+ rsmp->provider->get_next_buffer(rsmp->provider, &buf);
+ if (buf.raw == NULL) {
+ break;
+ }
+ memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
+ buf.raw,
+ buf.frame_count * rsmp->channel_count * sizeof(int16_t));
+ rsmp->frames_in += buf.frame_count;
+ rsmp->provider->release_buffer(rsmp->provider, &buf);
+ }
+
+ outFrames = framesRq - framesWr;
+ inFrames = rsmp->frames_in;
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ rsmp->in_buf,
+ (void *) &inFrames,
+ out + framesWr,
+ (void *) &outFrames);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ rsmp->in_buf,
+ (void *) &inFrames,
+ out + framesWr * rsmp->channel_count,
+ (void *) &outFrames);
+ }
+ framesWr += outFrames;
+ rsmp->frames_in -= inFrames;
+
+ if ((framesWr != framesRq) && (rsmp->frames_in != 0))
+ warn("ReSampler::resample() remaining %zd frames in and %zd out",
+ rsmp->frames_in, (framesRq - framesWr));
+ }
+ if (rsmp->frames_in) {
+ memmove(rsmp->in_buf,
+ rsmp->in_buf + inFrames * rsmp->channel_count,
+ rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
+ }
+ *outFrameCount = framesWr;
+
+ return 0;
+}
+
+static int resampler_resample_from_input(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
+ out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider != NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ in,
+ (void *) inFrameCount,
+ out,
+ (void *) outFrameCount);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ in,
+ (void *) inFrameCount,
+ out,
+ (void *) outFrameCount);
+ }
+
+ DBG("resampler_resample_from_input() DONE in %zd out %zd", *inFrameCount, *outFrameCount);
+
+ return 0;
+}
+
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider* provider,
+ struct resampler_itfe **resampler)
+{
+ int error;
+ struct resampler *rsmp;
+ int frames;
+
+ DBG("create_resampler() In SR %d Out SR %d channels %d",
+ inSampleRate, outSampleRate, channelCount);
+
+ if (resampler == NULL) {
+ return -EINVAL;
+ }
+
+ *resampler = NULL;
+
+ if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
+ return -EINVAL;
+ }
+
+ rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
+
+ rsmp->speex_resampler = speex_resampler_init(channelCount,
+ inSampleRate,
+ outSampleRate,
+ quality,
+ &error);
+ if (rsmp->speex_resampler == NULL) {
+ error("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
+ free(rsmp);
+ return -ENODEV;
+ }
+
+ rsmp->itfe.reset = resampler_reset;
+ rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
+ rsmp->itfe.resample_from_input = resampler_resample_from_input;
+ rsmp->itfe.delay_ns = resampler_delay_ns;
+
+ rsmp->provider = provider;
+ rsmp->in_sample_rate = inSampleRate;
+ rsmp->out_sample_rate = outSampleRate;
+ rsmp->channel_count = channelCount;
+ rsmp->in_buf = NULL;
+ rsmp->in_buf_size = 0;
+
+ resampler_reset(&rsmp->itfe);
+
+ frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
+ frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
+
+ *resampler = &rsmp->itfe;
+ DBG("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
+ rsmp, &rsmp->itfe, rsmp->speex_resampler);
+ return 0;
+}
+
+void release_resampler(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL) {
+ return;
+ }
+
+ free(rsmp->in_buf);
+
+ if (rsmp->speex_resampler != NULL) {
+ speex_resampler_destroy(rsmp->speex_resampler);
+ }
+ free(rsmp);
+}
diff --git a/repo/android/audio_utils/resampler.h b/repo/android/audio_utils/resampler.h
new file mode 100644
index 0000000..0c7046f
--- /dev/null
+++ b/repo/android/audio_utils/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frame_count;
+};
+
+/* call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+ /**
+ * get a new buffer of data:
+ * as input: buffer->frame_count is the number of frames requested
+ * as output: buffer->frame_count is the number of frames returned
+ * buffer->raw points to data returned
+ */
+ int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+ /**
+ * release a consumed buffer of data:
+ * as input: buffer->frame_count is the number of frames released
+ * buffer->raw points to data released
+ */
+ void (*release_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+};
+
+/* resampler interface */
+struct resampler_itfe {
+ /**
+ * reset resampler state
+ */
+ void (*reset)(struct resampler_itfe *resampler);
+ /**
+ * resample input from buffer provider and output at most *outFrameCount to out buffer.
+ * *outFrameCount is updated with the actual number of frames produced.
+ */
+ int (*resample_from_provider)(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * resample at most *inFrameCount frames from in buffer and output at most
+ * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+ * with the number of frames remaining in input and written to output.
+ */
+ int (*resample_from_input)(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * return the latency introduced by the resampler in ns.
+ */
+ int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider *provider,
+ struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/repo/android/avctp.c b/repo/android/avctp.c
new file mode 100644
index 0000000..6aa64cf
--- /dev/null
+++ b/repo/android/avctp.c
@@ -0,0 +1,1653 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+
+#include "lib/sdp.h"
+
+#include "src/log.h"
+#include "src/uinput.h"
+
+#include "avctp.h"
+
+/*
+ * AV/C Panel 1.23, page 76:
+ * command with the pressed value is valid for two seconds
+ */
+#define AVC_PRESS_TIMEOUT 2
+
+#define QUIRK_NO_RELEASE 1 << 0
+
+/* Message types */
+#define AVCTP_COMMAND 0
+#define AVCTP_RESPONSE 1
+
+/* Packet types */
+#define AVCTP_PACKET_SINGLE 0
+#define AVCTP_PACKET_START 1
+#define AVCTP_PACKET_CONTINUE 2
+#define AVCTP_PACKET_END 3
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avctp_header {
+ uint8_t ipid:1;
+ uint8_t cr:1;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint16_t pid;
+} __attribute__ ((packed));
+
+struct avc_header {
+ uint8_t code:4;
+ uint8_t _hdr0:4;
+ uint8_t subunit_id:3;
+ uint8_t subunit_type:5;
+ uint8_t opcode;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avctp_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t cr:1;
+ uint8_t ipid:1;
+ uint16_t pid;
+} __attribute__ ((packed));
+
+struct avc_header {
+ uint8_t _hdr0:4;
+ uint8_t code:4;
+ uint8_t subunit_type:5;
+ uint8_t subunit_id:3;
+ uint8_t opcode;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avctp_control_req {
+ struct avctp_pending_req *p;
+ uint8_t code;
+ uint8_t subunit;
+ uint8_t op;
+ struct iovec *iov;
+ int iov_cnt;
+ avctp_rsp_cb func;
+ void *user_data;
+};
+
+struct avctp_browsing_req {
+ struct avctp_pending_req *p;
+ struct iovec *iov;
+ int iov_cnt;
+ avctp_browsing_rsp_cb func;
+ void *user_data;
+};
+
+typedef int (*avctp_process_cb) (void *data);
+
+struct avctp_pending_req {
+ struct avctp_channel *chan;
+ uint8_t transaction;
+ guint timeout;
+ int err;
+ avctp_process_cb process;
+ void *data;
+ avctp_destroy_cb_t destroy;
+};
+
+struct avctp_channel {
+ struct avctp *session;
+ GIOChannel *io;
+ uint8_t transaction;
+ guint watch;
+ uint16_t imtu;
+ uint16_t omtu;
+ uint8_t *buffer;
+ GSList *handlers;
+ struct avctp_pending_req *p;
+ GQueue *queue;
+ GSList *processed;
+ guint process_id;
+ avctp_destroy_cb_t destroy;
+};
+
+struct key_pressed {
+ uint8_t op;
+ uint8_t *params;
+ size_t params_len;
+ guint timer;
+};
+
+struct avctp {
+ unsigned int ref;
+ int uinput;
+
+ unsigned int passthrough_id;
+ unsigned int unit_id;
+ unsigned int subunit_id;
+
+ struct avctp_channel *control;
+ struct avctp_channel *browsing;
+
+ struct avctp_passthrough_handler *handler;
+
+ uint8_t key_quirks[256];
+ struct key_pressed key;
+ uint16_t version;
+
+ avctp_destroy_cb_t destroy;
+ void *data;
+};
+
+struct avctp_passthrough_handler {
+ avctp_passthrough_cb cb;
+ void *user_data;
+ unsigned int id;
+};
+
+struct avctp_pdu_handler {
+ uint8_t opcode;
+ avctp_control_pdu_cb cb;
+ void *user_data;
+ unsigned int id;
+};
+
+struct avctp_browsing_pdu_handler {
+ avctp_browsing_pdu_cb cb;
+ void *user_data;
+ unsigned int id;
+ avctp_destroy_cb_t destroy;
+};
+
+static struct {
+ const char *name;
+ uint8_t avc;
+ uint16_t uinput;
+} key_map[] = {
+ { "SELECT", AVC_SELECT, KEY_SELECT },
+ { "UP", AVC_UP, KEY_UP },
+ { "DOWN", AVC_DOWN, KEY_DOWN },
+ { "LEFT", AVC_LEFT, KEY_LEFT },
+ { "RIGHT", AVC_RIGHT, KEY_RIGHT },
+ { "ROOT MENU", AVC_ROOT_MENU, KEY_MENU },
+ { "CONTENTS MENU", AVC_CONTENTS_MENU, KEY_PROGRAM },
+ { "FAVORITE MENU", AVC_FAVORITE_MENU, KEY_FAVORITES },
+ { "EXIT", AVC_EXIT, KEY_EXIT },
+ { "ON DEMAND MENU", AVC_ON_DEMAND_MENU, KEY_MENU },
+ { "APPS MENU", AVC_APPS_MENU, KEY_MENU },
+ { "0", AVC_0, KEY_0 },
+ { "1", AVC_1, KEY_1 },
+ { "2", AVC_2, KEY_2 },
+ { "3", AVC_3, KEY_3 },
+ { "4", AVC_4, KEY_4 },
+ { "5", AVC_5, KEY_5 },
+ { "6", AVC_6, KEY_6 },
+ { "7", AVC_7, KEY_7 },
+ { "8", AVC_8, KEY_8 },
+ { "9", AVC_9, KEY_9 },
+ { "DOT", AVC_DOT, KEY_DOT },
+ { "ENTER", AVC_ENTER, KEY_ENTER },
+ { "CHANNEL UP", AVC_CHANNEL_UP, KEY_CHANNELUP },
+ { "CHANNEL DOWN", AVC_CHANNEL_DOWN, KEY_CHANNELDOWN },
+ { "CHANNEL PREVIOUS", AVC_CHANNEL_PREVIOUS, KEY_LAST },
+ { "INPUT SELECT", AVC_INPUT_SELECT, KEY_CONFIG },
+ { "INFO", AVC_INFO, KEY_INFO },
+ { "HELP", AVC_HELP, KEY_HELP },
+ { "POWER", AVC_POWER, KEY_POWER2 },
+ { "VOLUME UP", AVC_VOLUME_UP, KEY_VOLUMEUP },
+ { "VOLUME DOWN", AVC_VOLUME_DOWN, KEY_VOLUMEDOWN },
+ { "MUTE", AVC_MUTE, KEY_MUTE },
+ { "PLAY", AVC_PLAY, KEY_PLAYCD },
+ { "STOP", AVC_STOP, KEY_STOPCD },
+ { "PAUSE", AVC_PAUSE, KEY_PAUSECD },
+ { "FORWARD", AVC_FORWARD, KEY_NEXTSONG },
+ { "BACKWARD", AVC_BACKWARD, KEY_PREVIOUSSONG },
+ { "RECORD", AVC_RECORD, KEY_RECORD },
+ { "REWIND", AVC_REWIND, KEY_REWIND },
+ { "FAST FORWARD", AVC_FAST_FORWARD, KEY_FASTFORWARD },
+ { "LIST", AVC_LIST, KEY_LIST },
+ { "F1", AVC_F1, KEY_F1 },
+ { "F2", AVC_F2, KEY_F2 },
+ { "F3", AVC_F3, KEY_F3 },
+ { "F4", AVC_F4, KEY_F4 },
+ { "F5", AVC_F5, KEY_F5 },
+ { "F6", AVC_F6, KEY_F6 },
+ { "F7", AVC_F7, KEY_F7 },
+ { "F8", AVC_F8, KEY_F8 },
+ { "F9", AVC_F9, KEY_F9 },
+ { "RED", AVC_RED, KEY_RED },
+ { "GREEN", AVC_GREEN, KEY_GREEN },
+ { "BLUE", AVC_BLUE, KEY_BLUE },
+ { "YELLOW", AVC_YELLOW, KEY_YELLOW },
+ { NULL }
+};
+
+static gboolean process_queue(gpointer user_data);
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+ uint8_t subunit, uint8_t *operands,
+ size_t operand_count, void *user_data);
+
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+ int err;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ do {
+ err = write(fd, &event, sizeof(event));
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ err = -errno;
+ error("send_event: %s (%d)", strerror(-err), -err);
+ }
+
+ return err;
+}
+
+static void send_key(int fd, uint16_t key, int pressed)
+{
+ send_event(fd, EV_KEY, key, pressed);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static gboolean auto_release(gpointer user_data)
+{
+ struct avctp *session = user_data;
+
+ session->key.timer = 0;
+
+ DBG("AV/C: key press timeout");
+
+ send_key(session->uinput, session->key.op, 0);
+
+ return FALSE;
+}
+
+static ssize_t handle_panel_passthrough(struct avctp *session,
+ uint8_t transaction, uint8_t *code,
+ uint8_t *subunit, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ struct avctp_passthrough_handler *handler = session->handler;
+ const char *status;
+ int pressed, i;
+
+ if (*code != AVC_CTYPE_CONTROL || *subunit != AVC_SUBUNIT_PANEL) {
+ *code = AVC_CTYPE_REJECTED;
+ return operand_count;
+ }
+
+ if (operand_count == 0)
+ goto done;
+
+ if (operands[0] & 0x80) {
+ status = "released";
+ pressed = 0;
+ } else {
+ status = "pressed";
+ pressed = 1;
+ }
+
+ if (session->key.timer == 0 && handler != NULL) {
+ if (handler->cb(session, operands[0] & 0x7F,
+ pressed, handler->user_data))
+ goto done;
+ }
+
+ if (session->uinput < 0) {
+ DBG("AV/C: uinput not initialized");
+ *code = AVC_CTYPE_NOT_IMPLEMENTED;
+ return 0;
+ }
+
+ for (i = 0; key_map[i].name != NULL; i++) {
+ uint8_t key_quirks;
+
+ if ((operands[0] & 0x7F) != key_map[i].avc)
+ continue;
+
+ DBG("AV/C: %s %s", key_map[i].name, status);
+
+ key_quirks = session->key_quirks[key_map[i].avc];
+
+ if (key_quirks & QUIRK_NO_RELEASE) {
+ if (!pressed) {
+ DBG("AV/C: Ignoring release");
+ break;
+ }
+
+ DBG("AV/C: treating key press as press + release");
+ send_key(session->uinput, key_map[i].uinput, 1);
+ send_key(session->uinput, key_map[i].uinput, 0);
+ break;
+ }
+
+ if (pressed) {
+ if (session->key.timer > 0) {
+ g_source_remove(session->key.timer);
+ send_key(session->uinput, session->key.op, 0);
+ }
+
+ session->key.op = key_map[i].uinput;
+ session->key.timer = g_timeout_add_seconds(
+ AVC_PRESS_TIMEOUT,
+ auto_release,
+ session);
+ } else if (session->key.timer > 0) {
+ g_source_remove(session->key.timer);
+ session->key.timer = 0;
+ }
+
+ send_key(session->uinput, key_map[i].uinput, pressed);
+ break;
+ }
+
+ if (key_map[i].name == NULL) {
+ DBG("AV/C: unknown button 0x%02X %s",
+ operands[0] & 0x7F, status);
+ *code = AVC_CTYPE_NOT_IMPLEMENTED;
+ return operand_count;
+ }
+
+done:
+ *code = AVC_CTYPE_ACCEPTED;
+ return operand_count;
+}
+
+static ssize_t handle_unit_info(struct avctp *session,
+ uint8_t transaction, uint8_t *code,
+ uint8_t *subunit, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ if (*code != AVC_CTYPE_STATUS) {
+ *code = AVC_CTYPE_REJECTED;
+ return 0;
+ }
+
+ *code = AVC_CTYPE_STABLE;
+
+ /*
+ * The first operand should be 0x07 for the UNITINFO response.
+ * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+ * Interface Command Set (section 9.2.1, page 45) specs
+ * explain this value but both use it
+ */
+ if (operand_count >= 1)
+ operands[0] = 0x07;
+ if (operand_count >= 2)
+ operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+ DBG("reply to AVC_OP_UNITINFO");
+
+ return operand_count;
+}
+
+static ssize_t handle_subunit_info(struct avctp *session,
+ uint8_t transaction, uint8_t *code,
+ uint8_t *subunit, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ if (*code != AVC_CTYPE_STATUS) {
+ *code = AVC_CTYPE_REJECTED;
+ return 0;
+ }
+
+ *code = AVC_CTYPE_STABLE;
+
+ /*
+ * The first operand should be 0x07 for the UNITINFO response.
+ * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+ * Interface Command Set (section 9.2.1, page 45) specs
+ * explain this value but both use it
+ */
+ if (operand_count >= 2)
+ operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+ DBG("reply to AVC_OP_SUBUNITINFO");
+
+ return operand_count;
+}
+
+static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
+{
+ for (; list; list = list->next) {
+ struct avctp_pdu_handler *handler = list->data;
+
+ if (handler->opcode == opcode)
+ return handler;
+ }
+
+ return NULL;
+}
+
+static void pending_destroy(gpointer data, gpointer user_data)
+{
+ struct avctp_pending_req *req = data;
+
+ if (req->destroy)
+ req->destroy(req->data);
+
+ if (req->timeout > 0)
+ g_source_remove(req->timeout);
+
+ g_free(req);
+}
+
+static void avctp_channel_destroy(struct avctp_channel *chan)
+{
+ g_io_channel_shutdown(chan->io, TRUE, NULL);
+ g_io_channel_unref(chan->io);
+
+ if (chan->watch)
+ g_source_remove(chan->watch);
+
+ if (chan->p)
+ pending_destroy(chan->p, NULL);
+
+ if (chan->process_id > 0)
+ g_source_remove(chan->process_id);
+
+ if (chan->destroy)
+ chan->destroy(chan);
+
+ g_free(chan->buffer);
+ g_queue_foreach(chan->queue, pending_destroy, NULL);
+ g_queue_free(chan->queue);
+ g_slist_foreach(chan->processed, pending_destroy, NULL);
+ g_slist_free(chan->processed);
+ g_slist_free_full(chan->handlers, g_free);
+ g_free(chan);
+}
+
+static int avctp_send(struct avctp_channel *control, uint8_t transaction,
+ uint8_t cr, uint8_t code,
+ uint8_t subunit, uint8_t opcode,
+ const struct iovec *iov, int iov_cnt)
+{
+ struct avctp_header avctp;
+ struct avc_header avc;
+ struct msghdr msg;
+ int sk, err = 0;
+ struct iovec pdu[iov_cnt + 2];
+ int i;
+ size_t len = sizeof(avctp) + sizeof(avc);
+
+ DBG("");
+
+ pdu[0].iov_base = &avctp;
+ pdu[0].iov_len = sizeof(avctp);
+ pdu[1].iov_base = &avc;
+ pdu[1].iov_len = sizeof(avc);
+
+ for (i = 0; i < iov_cnt; i++) {
+ pdu[i + 2].iov_base = iov[i].iov_base;
+ pdu[i + 2].iov_len = iov[i].iov_len;
+ len += iov[i].iov_len;
+ }
+
+ if (control->omtu < len)
+ return -EOVERFLOW;
+
+ sk = g_io_channel_unix_get_fd(control->io);
+
+ memset(&avctp, 0, sizeof(avctp));
+
+ avctp.transaction = transaction;
+ avctp.packet_type = AVCTP_PACKET_SINGLE;
+ avctp.cr = cr;
+ avctp.pid = htons(AV_REMOTE_SVCLASS_ID);
+
+ memset(&avc, 0, sizeof(avc));
+
+ avc.code = code;
+ avc.subunit_type = subunit;
+ avc.opcode = opcode;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = pdu;
+ msg.msg_iovlen = iov_cnt + 2;
+
+ if (sendmsg(sk, &msg, 0) < 0)
+ err = -errno;
+
+ return err;
+}
+
+static int avctp_browsing_send(struct avctp_channel *browsing,
+ uint8_t transaction, uint8_t cr,
+ const struct iovec *iov, int iov_cnt)
+{
+ struct avctp_header avctp;
+ struct msghdr msg;
+ struct iovec pdu[iov_cnt + 1];
+ int sk, err = 0;
+ int i;
+ size_t len = sizeof(avctp);
+
+ for (i = 0; i < iov_cnt; i++) {
+ pdu[i + 1].iov_base = iov[i].iov_base;
+ pdu[i + 1].iov_len = iov[i].iov_len;
+ len += iov[i].iov_len;
+ }
+
+ pdu[0].iov_base = &avctp;
+ pdu[0].iov_len = sizeof(avctp);
+
+ if (browsing->omtu < len)
+ return -EOVERFLOW;
+
+ sk = g_io_channel_unix_get_fd(browsing->io);
+
+ memset(&avctp, 0, sizeof(avctp));
+
+ avctp.transaction = transaction;
+ avctp.packet_type = AVCTP_PACKET_SINGLE;
+ avctp.cr = cr;
+ avctp.pid = htons(AV_REMOTE_SVCLASS_ID);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = pdu;
+ msg.msg_iovlen = iov_cnt + 1;
+
+ if (sendmsg(sk, &msg, 0) < 0)
+ err = -errno;
+
+ return err;
+}
+
+static void control_req_destroy(void *data)
+{
+ struct avctp_control_req *req = data;
+ struct avctp_pending_req *p = req->p;
+ struct avctp *session = p->chan->session;
+ int i;
+
+ if (p->err == 0 || req->func == NULL)
+ goto done;
+
+ req->func(session, AVC_CTYPE_REJECTED, req->subunit, NULL, 0,
+ req->user_data);
+
+done:
+ for (i = 0; i < req->iov_cnt; i++)
+ g_free(req->iov[i].iov_base);
+
+ g_free(req->iov);
+ g_free(req);
+}
+
+static void browsing_req_destroy(void *data)
+{
+ struct avctp_browsing_req *req = data;
+ struct avctp_pending_req *p = req->p;
+ struct avctp *session = p->chan->session;
+ int i;
+
+ if (p->err == 0 || req->func == NULL)
+ goto done;
+
+ req->func(session, NULL, 0, req->user_data);
+
+done:
+ for (i = 0; i < req->iov_cnt; i++)
+ g_free(req->iov[i].iov_base);
+
+ g_free(req->iov);
+ g_free(req);
+}
+
+static gboolean req_timeout(gpointer user_data)
+{
+ struct avctp_channel *chan = user_data;
+ struct avctp_pending_req *p = chan->p;
+
+ DBG("transaction %u", p->transaction);
+
+ p->timeout = 0;
+ p->err = -ETIMEDOUT;
+
+ pending_destroy(p, NULL);
+ chan->p = NULL;
+
+ if (chan->process_id == 0)
+ chan->process_id = g_idle_add(process_queue, chan);
+
+ return FALSE;
+}
+
+static int process_control(void *data)
+{
+ struct avctp_control_req *req = data;
+ struct avctp_pending_req *p = req->p;
+
+ return avctp_send(p->chan, p->transaction, AVCTP_COMMAND, req->code,
+ req->subunit, req->op, req->iov, req->iov_cnt);
+}
+
+static int process_browsing(void *data)
+{
+ struct avctp_browsing_req *req = data;
+ struct avctp_pending_req *p = req->p;
+
+ return avctp_browsing_send(p->chan, p->transaction, AVCTP_COMMAND,
+ req->iov, req->iov_cnt);
+}
+
+static gboolean process_queue(void *user_data)
+{
+ struct avctp_channel *chan = user_data;
+ struct avctp_pending_req *p = chan->p;
+
+ chan->process_id = 0;
+
+ if (p != NULL)
+ return FALSE;
+
+ while ((p = g_queue_pop_head(chan->queue))) {
+
+ if (p->process(p->data) == 0)
+ break;
+
+ pending_destroy(p, NULL);
+ }
+
+ if (p == NULL)
+ return FALSE;
+
+ chan->p = p;
+ p->timeout = g_timeout_add_seconds(2, req_timeout, chan);
+
+ return FALSE;
+
+}
+
+static struct avctp *avctp_ref(struct avctp *session)
+{
+ __sync_fetch_and_add(&session->ref, 1);
+
+ DBG("%p: ref=%d", session, session->ref);
+
+ return session;
+}
+
+static void avctp_unref(struct avctp *session)
+{
+ DBG("%p: ref=%d", session, session->ref);
+
+ if (__sync_sub_and_fetch(&session->ref, 1))
+ return;
+
+ if (session->browsing)
+ avctp_channel_destroy(session->browsing);
+
+ if (session->control)
+ avctp_channel_destroy(session->control);
+
+ if (session->destroy)
+ session->destroy(session->data);
+
+ g_free(session->handler);
+
+ if (session->key.timer > 0)
+ g_source_remove(session->key.timer);
+
+ if (session->uinput >= 0) {
+ DBG("AVCTP: closing uinput");
+
+ ioctl(session->uinput, UI_DEV_DESTROY);
+ close(session->uinput);
+ session->uinput = -1;
+ }
+
+ g_free(session);
+}
+
+static void control_response(struct avctp_channel *control,
+ struct avctp_header *avctp,
+ struct avc_header *avc,
+ uint8_t *operands,
+ size_t operand_count)
+{
+ struct avctp_pending_req *p = control->p;
+ struct avctp_control_req *req;
+ GSList *l;
+
+ if (p && p->transaction == avctp->transaction) {
+ control->processed = g_slist_prepend(control->processed, p);
+
+ if (p->timeout > 0) {
+ g_source_remove(p->timeout);
+ p->timeout = 0;
+ }
+
+ control->p = NULL;
+
+ if (control->process_id == 0)
+ control->process_id = g_idle_add(process_queue,
+ control);
+ }
+
+ avctp_ref(control->session);
+
+ for (l = control->processed; l; l = l->next) {
+ p = l->data;
+ req = p->data;
+
+ if (p->transaction != avctp->transaction)
+ continue;
+
+ if (req->func && req->func(control->session, avc->code,
+ avc->subunit_type,
+ operands, operand_count,
+ req->user_data))
+ break;
+
+ control->processed = g_slist_remove(control->processed, p);
+ pending_destroy(p, NULL);
+
+ break;
+ }
+
+ avctp_unref(control->session);
+}
+
+static void browsing_response(struct avctp_channel *browsing,
+ struct avctp_header *avctp,
+ uint8_t *operands,
+ size_t operand_count)
+{
+ struct avctp_pending_req *p = browsing->p;
+ struct avctp_browsing_req *req;
+ GSList *l;
+
+ if (p && p->transaction == avctp->transaction) {
+ browsing->processed = g_slist_prepend(browsing->processed, p);
+
+ if (p->timeout > 0) {
+ g_source_remove(p->timeout);
+ p->timeout = 0;
+ }
+
+ browsing->p = NULL;
+
+ if (browsing->process_id == 0)
+ browsing->process_id = g_idle_add(process_queue,
+ browsing);
+ }
+
+ avctp_ref(browsing->session);
+
+ for (l = browsing->processed; l; l = l->next) {
+ p = l->data;
+ req = p->data;
+
+ if (p->transaction != avctp->transaction)
+ continue;
+
+ if (req->func && req->func(browsing->session, operands,
+ operand_count, req->user_data))
+ break;
+
+ browsing->processed = g_slist_remove(browsing->processed, p);
+ pending_destroy(p, NULL);
+
+ break;
+ }
+
+ avctp_unref(browsing->session);
+}
+
+static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avctp *session = data;
+ struct avctp_channel *browsing = session->browsing;
+ uint8_t *buf = browsing->buffer;
+ uint8_t *operands;
+ struct avctp_header *avctp;
+ int sock, ret, packet_size, operand_count;
+ struct avctp_browsing_pdu_handler *handler;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ goto failed;
+
+ sock = g_io_channel_unix_get_fd(chan);
+
+ ret = read(sock, buf, browsing->imtu);
+ if (ret <= 0)
+ goto failed;
+
+ if (ret < AVCTP_HEADER_LENGTH) {
+ error("Too small AVCTP packet");
+ goto failed;
+ }
+
+ avctp = (struct avctp_header *) buf;
+
+ if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
+ error("Invalid packet type");
+ goto failed;
+ }
+
+ operands = buf + AVCTP_HEADER_LENGTH;
+ ret -= AVCTP_HEADER_LENGTH;
+ operand_count = ret;
+
+ if (avctp->cr == AVCTP_RESPONSE) {
+ browsing_response(browsing, avctp, operands, operand_count);
+ return TRUE;
+ }
+
+ packet_size = AVCTP_HEADER_LENGTH;
+ avctp->cr = AVCTP_RESPONSE;
+
+ handler = g_slist_nth_data(browsing->handlers, 0);
+ if (handler == NULL) {
+ DBG("handler not found");
+ /* FIXME: Add general reject */
+ /* packet_size += avrcp_browsing_general_reject(operands); */
+ goto send;
+ }
+
+ ret = handler->cb(session, avctp->transaction, operands, operand_count,
+ handler->user_data);
+ if (ret < 0) {
+ if (ret == -EAGAIN)
+ return TRUE;
+ goto failed;
+ }
+
+ packet_size += ret;
+
+send:
+ if (packet_size != 0) {
+ ret = write(sock, buf, packet_size);
+ if (ret != packet_size)
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ DBG("AVCTP Browsing: disconnected");
+
+ if (session->browsing) {
+ avctp_channel_destroy(session->browsing);
+ session->browsing = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct avctp *session = data;
+ struct avctp_channel *control = session->control;
+ uint8_t *buf = control->buffer;
+ uint8_t *operands, code, subunit;
+ struct avctp_header *avctp;
+ struct avc_header *avc;
+ int packet_size, operand_count, sock;
+ struct avctp_pdu_handler *handler;
+ ssize_t ret;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ goto failed;
+
+ sock = g_io_channel_unix_get_fd(chan);
+
+ ret = read(sock, buf, control->imtu);
+ if (ret <= 0)
+ goto failed;
+
+ if (ret < AVCTP_HEADER_LENGTH) {
+ error("Too small AVCTP packet");
+ goto failed;
+ }
+
+ avctp = (struct avctp_header *) buf;
+
+ ret -= AVCTP_HEADER_LENGTH;
+ if (ret < AVC_HEADER_LENGTH) {
+ error("Too small AVC packet");
+ goto failed;
+ }
+
+ avc = (struct avc_header *) (buf + AVCTP_HEADER_LENGTH);
+
+ ret -= AVC_HEADER_LENGTH;
+
+ operands = (uint8_t *) avc + AVC_HEADER_LENGTH;
+ operand_count = ret;
+
+ if (avctp->cr == AVCTP_RESPONSE) {
+ control_response(control, avctp, avc, operands, operand_count);
+ return TRUE;
+ }
+
+ packet_size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH;
+ avctp->cr = AVCTP_RESPONSE;
+
+ if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
+ avc->code = AVC_CTYPE_NOT_IMPLEMENTED;
+ goto done;
+ }
+
+ if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
+ avctp->ipid = 1;
+ packet_size = AVCTP_HEADER_LENGTH;
+ goto done;
+ }
+
+ handler = find_handler(control->handlers, avc->opcode);
+ if (!handler) {
+ DBG("handler not found for 0x%02x", avc->opcode);
+ avc->code = AVC_CTYPE_REJECTED;
+ goto done;
+ }
+
+ code = avc->code;
+ subunit = avc->subunit_type;
+
+ ret = handler->cb(session, avctp->transaction, &code,
+ &subunit, operands, operand_count,
+ handler->user_data);
+ if (ret < 0) {
+ if (ret == -EAGAIN)
+ return TRUE;
+ goto failed;
+ }
+
+ packet_size += ret;
+ avc->code = code;
+ avc->subunit_type = subunit;
+
+done:
+ ret = write(sock, buf, packet_size);
+ if (ret != packet_size)
+ goto failed;
+
+ return TRUE;
+
+failed:
+ DBG("AVCTP session %p got disconnected", session);
+ avctp_shutdown(session);
+ return FALSE;
+}
+
+static int uinput_create(const char *name)
+{
+ struct uinput_dev dev;
+ int fd, err, i;
+
+ fd = open("/dev/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/input/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/misc/uinput", O_RDWR);
+ if (fd < 0) {
+ err = -errno;
+ error("Can't open input device: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ }
+ }
+
+ memset(&dev, 0, sizeof(dev));
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ err = -errno;
+ error("Can't write device information: %s (%d)",
+ strerror(-err), -err);
+ close(fd);
+ return err;
+ }
+
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_REP);
+ ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+ for (i = 0; key_map[i].name != NULL; i++)
+ ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
+
+ if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+ err = -errno;
+ error("Can't create uinput device: %s (%d)",
+ strerror(-err), -err);
+ close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+int avctp_init_uinput(struct avctp *session, const char *name,
+ const char *address)
+{
+ if (g_str_equal(name, "Nokia CK-20W")) {
+ session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE;
+ session->key_quirks[AVC_BACKWARD] |= QUIRK_NO_RELEASE;
+ session->key_quirks[AVC_PLAY] |= QUIRK_NO_RELEASE;
+ session->key_quirks[AVC_PAUSE] |= QUIRK_NO_RELEASE;
+ }
+
+ session->uinput = uinput_create(address);
+ if (session->uinput < 0) {
+ error("AVCTP: failed to init uinput for %s", address);
+ return session->uinput;
+ }
+
+ return 0;
+}
+
+static struct avctp_channel *avctp_channel_create(struct avctp *session, int fd,
+ size_t imtu, size_t omtu,
+ avctp_destroy_cb_t destroy)
+{
+ struct avctp_channel *chan;
+
+ chan = g_new0(struct avctp_channel, 1);
+ chan->session = session;
+ chan->io = g_io_channel_unix_new(fd);
+ chan->queue = g_queue_new();
+ chan->imtu = imtu;
+ chan->omtu = omtu;
+ chan->buffer = g_malloc0(MAX(imtu, omtu));
+ chan->destroy = destroy;
+
+ return chan;
+}
+
+static void handler_free(void *data)
+{
+ struct avctp_browsing_pdu_handler *handler = data;
+
+ if (handler->destroy)
+ handler->destroy(handler->user_data);
+
+ g_free(data);
+}
+
+static void avctp_destroy_browsing(void *data)
+{
+ struct avctp_channel *chan = data;
+
+ g_slist_free_full(chan->handlers, handler_free);
+
+ chan->handlers = NULL;
+}
+
+static struct avctp_pending_req *pending_create(struct avctp_channel *chan,
+ avctp_process_cb process,
+ void *data,
+ avctp_destroy_cb_t destroy)
+{
+ struct avctp_pending_req *p;
+ GSList *l, *tmp;
+
+ if (!chan->processed)
+ goto done;
+
+ tmp = g_slist_copy(chan->processed);
+
+ /* Find first unused transaction id */
+ for (l = tmp; l; l = g_slist_next(l)) {
+ struct avctp_pending_req *req = l->data;
+
+ if (req->transaction == chan->transaction) {
+ chan->transaction++;
+ chan->transaction %= 16;
+ tmp = g_slist_delete_link(tmp, l);
+ l = tmp;
+ }
+ }
+
+ g_slist_free(tmp);
+
+done:
+ p = g_new0(struct avctp_pending_req, 1);
+ p->chan = chan;
+ p->transaction = chan->transaction;
+ p->process = process;
+ p->data = data;
+ p->destroy = destroy;
+
+ chan->transaction++;
+ chan->transaction %= 16;
+
+ return p;
+}
+
+static int avctp_send_req(struct avctp *session, uint8_t code, uint8_t subunit,
+ uint8_t opcode, const struct iovec *iov, int iov_cnt,
+ avctp_rsp_cb func, void *user_data)
+{
+ struct avctp_channel *control = session->control;
+ struct avctp_pending_req *p;
+ struct avctp_control_req *req;
+ struct iovec *pdu;
+ int i;
+
+ if (control == NULL)
+ return -ENOTCONN;
+
+ pdu = g_new0(struct iovec, iov_cnt);
+
+ for (i = 0; i < iov_cnt; i++) {
+ pdu[i].iov_len = iov[i].iov_len;
+ pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len);
+ }
+
+ req = g_new0(struct avctp_control_req, 1);
+ req->code = code;
+ req->subunit = subunit;
+ req->op = opcode;
+ req->func = func;
+ req->iov = pdu;
+ req->iov_cnt = iov_cnt;
+ req->user_data = user_data;
+
+ p = pending_create(control, process_control, req, control_req_destroy);
+
+ req->p = p;
+
+ g_queue_push_tail(control->queue, p);
+
+ if (control->process_id == 0)
+ control->process_id = g_idle_add(process_queue, control);
+
+ return 0;
+}
+
+int avctp_send_browsing_req(struct avctp *session,
+ const struct iovec *iov, int iov_cnt,
+ avctp_browsing_rsp_cb func, void *user_data)
+{
+ struct avctp_channel *browsing = session->browsing;
+ struct avctp_pending_req *p;
+ struct avctp_browsing_req *req;
+ struct iovec *pdu;
+ int i;
+
+ if (browsing == NULL)
+ return -ENOTCONN;
+
+ pdu = g_new0(struct iovec, iov_cnt);
+
+ for (i = 0; i < iov_cnt; i++) {
+ pdu[i].iov_len = iov[i].iov_len;
+ pdu[i].iov_base = g_memdup(iov[i].iov_base, iov[i].iov_len);
+ }
+
+ req = g_new0(struct avctp_browsing_req, 1);
+ req->func = func;
+ req->iov = pdu;
+ req->iov_cnt = iov_cnt;
+ req->user_data = user_data;
+
+ p = pending_create(browsing, process_browsing, req,
+ browsing_req_destroy);
+
+ req->p = p;
+
+ g_queue_push_tail(browsing->queue, p);
+
+ /* Connection did not complete, delay process of the request */
+ if (browsing->watch == 0)
+ return 0;
+
+ if (browsing->process_id == 0)
+ browsing->process_id = g_idle_add(process_queue, browsing);
+
+ return 0;
+}
+
+int avctp_send_browsing(struct avctp *session, uint8_t transaction,
+ const struct iovec *iov, int iov_cnt)
+{
+ struct avctp_channel *browsing = session->browsing;
+
+ if (browsing == NULL)
+ return -ENOTCONN;
+
+ return avctp_browsing_send(browsing, transaction, AVCTP_RESPONSE,
+ iov, iov_cnt);
+}
+
+static const char *op2str(uint8_t op)
+{
+ int i;
+
+ for (i = 0; key_map[i].name != NULL; i++) {
+ if ((op & 0x7F) == key_map[i].avc)
+ return key_map[i].name;
+ }
+
+ return "UNKNOWN";
+}
+
+static int avctp_passthrough_press(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
+{
+ struct iovec iov[2];
+ int iov_cnt;
+ uint8_t operands[2];
+
+ DBG("%s", op2str(op));
+
+ iov[0].iov_base = operands;
+ iov[0].iov_len = sizeof(operands);
+
+ /* Button pressed */
+ operands[0] = op & 0x7f;
+
+ if (params_len > 0) {
+ iov[1].iov_base = params;
+ iov[1].iov_len = params_len;
+ iov_cnt = 2;
+ operands[1] = params_len;
+ } else {
+ iov_cnt = 1;
+ operands[1] = 0;
+ }
+
+ return avctp_send_req(session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+ iov, iov_cnt, avctp_passthrough_rsp, NULL);
+}
+
+static int avctp_passthrough_release(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
+{
+ struct iovec iov[2];
+ int iov_cnt;
+ uint8_t operands[2];
+
+ DBG("%s", op2str(op));
+
+ iov[0].iov_base = operands;
+ iov[0].iov_len = sizeof(operands);
+
+ /* Button released */
+ operands[0] = op | 0x80;
+
+ if (params_len > 0) {
+ iov[1].iov_base = params;
+ iov[1].iov_len = params_len;
+ iov_cnt = 2;
+ operands[1] = params_len;
+ } else {
+ iov_cnt = 1;
+ operands[1] = 0;
+ }
+
+ return avctp_send_req(session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+ iov, iov_cnt, NULL, NULL);
+}
+
+static gboolean repeat_timeout(gpointer user_data)
+{
+ struct avctp *session = user_data;
+
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
+ avctp_passthrough_press(session, session->key.op, session->key.params,
+ session->key.params_len);
+
+ return TRUE;
+}
+
+static void release_pressed(struct avctp *session)
+{
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
+
+ if (session->key.timer > 0)
+ g_source_remove(session->key.timer);
+
+ session->key.timer = 0;
+}
+
+static bool set_pressed(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
+{
+ if (session->key.timer > 0) {
+ if (session->key.op == op)
+ return TRUE;
+ release_pressed(session);
+ }
+
+ if (op != AVC_FAST_FORWARD && op != AVC_REWIND)
+ return FALSE;
+
+ session->key.op = op;
+ session->key.params = params;
+ session->key.params_len = params_len;
+ session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
+ repeat_timeout,
+ session);
+
+ return TRUE;
+}
+
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+ uint8_t subunit, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ uint8_t *params;
+ size_t params_len;
+
+ DBG("code 0x%02x operand_count %zd", code, operand_count);
+
+ if (code != AVC_CTYPE_ACCEPTED)
+ return FALSE;
+
+ if (operands[0] == AVC_VENDOR_UNIQUE) {
+ params = &operands[2];
+ params_len = operand_count - 2;
+ } else {
+ params = NULL;
+ params_len = 0;
+ }
+
+ if (set_pressed(session, operands[0], params, params_len))
+ return FALSE;
+
+ avctp_passthrough_release(session, operands[0], params, params_len);
+
+ return FALSE;
+}
+
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
+{
+ /* Auto release if key pressed */
+ if (session->key.timer > 0)
+ release_pressed(session);
+
+ return avctp_passthrough_press(session, op, params, params_len);
+}
+
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
+ uint8_t code, uint8_t subunit,
+ const struct iovec *iov, int iov_cnt)
+{
+ struct avctp_channel *control = session->control;
+
+ if (control == NULL)
+ return -ENOTCONN;
+
+ return avctp_send(control, transaction, AVCTP_RESPONSE, code, subunit,
+ AVC_OP_VENDORDEP, iov, iov_cnt);
+}
+
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+ const struct iovec *iov, int iov_cnt,
+ avctp_rsp_cb func, void *user_data)
+{
+ return avctp_send_req(session, code, subunit, AVC_OP_VENDORDEP, iov,
+ iov_cnt, func, user_data);
+}
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+ avctp_passthrough_cb cb,
+ void *user_data)
+{
+ struct avctp_channel *control = session->control;
+ struct avctp_passthrough_handler *handler;
+ static unsigned int id = 0;
+
+ if (control == NULL || session->handler != NULL)
+ return 0;
+
+ handler = g_new(struct avctp_passthrough_handler, 1);
+ handler->cb = cb;
+ handler->user_data = user_data;
+ handler->id = ++id;
+
+ session->handler = handler;
+
+ return handler->id;
+}
+
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+ unsigned int id)
+{
+ if (session->handler == NULL)
+ return false;
+
+ if (session->handler->id != id)
+ return false;
+
+ g_free(session->handler);
+ session->handler = NULL;
+ return true;
+}
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+ avctp_control_pdu_cb cb,
+ void *user_data)
+{
+ struct avctp_channel *control = session->control;
+ struct avctp_pdu_handler *handler;
+ static unsigned int id = 0;
+
+ if (control == NULL)
+ return 0;
+
+ handler = find_handler(control->handlers, opcode);
+ if (handler)
+ return 0;
+
+ handler = g_new(struct avctp_pdu_handler, 1);
+ handler->opcode = opcode;
+ handler->cb = cb;
+ handler->user_data = user_data;
+ handler->id = ++id;
+
+ control->handlers = g_slist_append(control->handlers, handler);
+
+ return handler->id;
+}
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+ avctp_browsing_pdu_cb cb,
+ void *user_data,
+ avctp_destroy_cb_t destroy)
+{
+ struct avctp_channel *browsing = session->browsing;
+ struct avctp_browsing_pdu_handler *handler;
+ static unsigned int id = 0;
+
+ if (browsing == NULL)
+ return 0;
+
+ if (browsing->handlers != NULL)
+ return 0;
+
+ handler = g_new(struct avctp_browsing_pdu_handler, 1);
+ handler->cb = cb;
+ handler->user_data = user_data;
+ handler->id = ++id;
+ handler->destroy = destroy;
+
+ browsing->handlers = g_slist_append(browsing->handlers, handler);
+
+ return handler->id;
+}
+
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id)
+{
+ struct avctp_channel *control = session->control;
+ GSList *l;
+
+ if (!control)
+ return false;
+
+ for (l = control->handlers; l; l = g_slist_next(l)) {
+ struct avctp_pdu_handler *handler = l->data;
+
+ if (handler->id != id)
+ continue;
+
+ control->handlers = g_slist_remove(control->handlers, handler);
+ g_free(handler);
+ return true;
+ }
+
+ return false;
+}
+
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+ unsigned int id)
+{
+ struct avctp_channel *browsing = session->browsing;
+ GSList *l;
+
+ if (browsing == NULL)
+ return false;
+
+ for (l = browsing->handlers; l; l = g_slist_next(l)) {
+ struct avctp_browsing_pdu_handler *handler = l->data;
+
+ if (handler->id != id)
+ continue;
+
+ browsing->handlers = g_slist_remove(browsing->handlers,
+ handler);
+ g_free(handler);
+ return true;
+ }
+
+ return false;
+}
+
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
+{
+ struct avctp *session;
+ struct avctp_channel *control;
+ GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+ session = g_new0(struct avctp, 1);
+ session->version = version;
+
+ control = avctp_channel_create(session, fd, imtu, omtu, NULL);
+ if (!control) {
+ g_free(session);
+ return NULL;
+ }
+
+ session->uinput = -1;
+ session->control = control;
+ session->passthrough_id = avctp_register_pdu_handler(session,
+ AVC_OP_PASSTHROUGH,
+ handle_panel_passthrough,
+ NULL);
+ session->unit_id = avctp_register_pdu_handler(session,
+ AVC_OP_UNITINFO,
+ handle_unit_info,
+ NULL);
+ session->subunit_id = avctp_register_pdu_handler(session,
+ AVC_OP_SUBUNITINFO,
+ handle_subunit_info,
+ NULL);
+
+ control->watch = g_io_add_watch(session->control->io, cond,
+ (GIOFunc) session_cb, session);
+
+ return avctp_ref(session);
+}
+
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+ size_t omtu)
+{
+ struct avctp_channel *browsing;
+ GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+ if (session->browsing)
+ return -EISCONN;
+
+ browsing = avctp_channel_create(session, fd, imtu, omtu,
+ avctp_destroy_browsing);
+ if (!browsing)
+ return -EINVAL;
+
+ session->browsing = browsing;
+ browsing->watch = g_io_add_watch(session->browsing->io, cond,
+ (GIOFunc) session_browsing_cb, session);
+
+ return 0;
+}
+
+void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb,
+ void *user_data)
+{
+ session->destroy = cb;
+ session->data = user_data;
+}
+
+void avctp_shutdown(struct avctp *session)
+{
+ if (!session)
+ return;
+
+ avctp_unref(session);
+}
diff --git a/repo/android/avctp.h b/repo/android/avctp.h
new file mode 100644
index 0000000..f0da2b3
--- /dev/null
+++ b/repo/android/avctp.h
@@ -0,0 +1,183 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AVCTP_CONTROL_PSM 23
+#define AVCTP_BROWSING_PSM 27
+
+#define AVCTP_HEADER_LENGTH 3
+#define AVC_HEADER_LENGTH 3
+
+#define AVC_DATA_OFFSET AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH
+#define AVC_DATA_MTU 512
+
+/* ctype entries */
+#define AVC_CTYPE_CONTROL 0x0
+#define AVC_CTYPE_STATUS 0x1
+#define AVC_CTYPE_NOTIFY 0x3
+#define AVC_CTYPE_NOT_IMPLEMENTED 0x8
+#define AVC_CTYPE_ACCEPTED 0x9
+#define AVC_CTYPE_REJECTED 0xA
+#define AVC_CTYPE_STABLE 0xC
+#define AVC_CTYPE_CHANGED 0xD
+#define AVC_CTYPE_INTERIM 0xF
+
+/* opcodes */
+#define AVC_OP_VENDORDEP 0x00
+#define AVC_OP_UNITINFO 0x30
+#define AVC_OP_SUBUNITINFO 0x31
+#define AVC_OP_PASSTHROUGH 0x7c
+
+/* subunits of interest */
+#define AVC_SUBUNIT_PANEL 0x09
+
+/* operands in passthrough commands */
+#define AVC_SELECT 0x00
+#define AVC_UP 0x01
+#define AVC_DOWN 0x02
+#define AVC_LEFT 0x03
+#define AVC_RIGHT 0x04
+#define AVC_ROOT_MENU 0x09
+#define AVC_CONTENTS_MENU 0x0b
+#define AVC_FAVORITE_MENU 0x0c
+#define AVC_EXIT 0x0d
+#define AVC_ON_DEMAND_MENU 0x0e
+#define AVC_APPS_MENU 0x0f
+#define AVC_0 0x20
+#define AVC_1 0x21
+#define AVC_2 0x22
+#define AVC_3 0x23
+#define AVC_4 0x24
+#define AVC_5 0x25
+#define AVC_6 0x26
+#define AVC_7 0x27
+#define AVC_8 0x28
+#define AVC_9 0x29
+#define AVC_DOT 0x2a
+#define AVC_ENTER 0x2b
+#define AVC_CHANNEL_UP 0x30
+#define AVC_CHANNEL_DOWN 0x31
+#define AVC_CHANNEL_PREVIOUS 0x32
+#define AVC_INPUT_SELECT 0x34
+#define AVC_INFO 0x35
+#define AVC_HELP 0x36
+#define AVC_PAGE_UP 0x37
+#define AVC_PAGE_DOWN 0x38
+#define AVC_LOCK 0x3a
+#define AVC_POWER 0x40
+#define AVC_VOLUME_UP 0x41
+#define AVC_VOLUME_DOWN 0x42
+#define AVC_MUTE 0x43
+#define AVC_PLAY 0x44
+#define AVC_STOP 0x45
+#define AVC_PAUSE 0x46
+#define AVC_RECORD 0x47
+#define AVC_REWIND 0x48
+#define AVC_FAST_FORWARD 0x49
+#define AVC_EJECT 0x4a
+#define AVC_FORWARD 0x4b
+#define AVC_BACKWARD 0x4c
+#define AVC_LIST 0x4d
+#define AVC_F1 0x71
+#define AVC_F2 0x72
+#define AVC_F3 0x73
+#define AVC_F4 0x74
+#define AVC_F5 0x75
+#define AVC_F6 0x76
+#define AVC_F7 0x77
+#define AVC_F8 0x78
+#define AVC_F9 0x79
+#define AVC_RED 0x7a
+#define AVC_GREEN 0x7b
+#define AVC_BLUE 0x7c
+#define AVC_YELLOW 0x7c
+
+#define AVC_VENDOR_UNIQUE 0x7e
+
+#define AVC_VENDOR_NEXT_GROUP 0x00
+#define AVC_VENDOR_PREV_GROUP 0x01
+
+struct avctp;
+
+typedef bool (*avctp_passthrough_cb) (struct avctp *session,
+ uint8_t op, bool pressed,
+ void *user_data);
+typedef ssize_t (*avctp_control_pdu_cb) (struct avctp *session,
+ uint8_t transaction, uint8_t *code,
+ uint8_t *subunit, uint8_t *operands,
+ size_t operand_count, void *user_data);
+typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
+ uint8_t subunit, uint8_t *operands,
+ size_t operand_count, void *user_data);
+typedef gboolean (*avctp_browsing_rsp_cb) (struct avctp *session,
+ uint8_t *operands, size_t operand_count,
+ void *user_data);
+typedef ssize_t (*avctp_browsing_pdu_cb) (struct avctp *session,
+ uint8_t transaction,
+ uint8_t *operands, size_t operand_count,
+ void *user_data);
+
+typedef void (*avctp_destroy_cb_t) (void *user_data);
+
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+void avctp_set_destroy_cb(struct avctp *session, avctp_destroy_cb_t cb,
+ void *user_data);
+
+int avctp_init_uinput(struct avctp *session, const char *name,
+ const char *address);
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+ size_t omtu);
+
+void avctp_shutdown(struct avctp *session);
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+ avctp_passthrough_cb cb,
+ void *user_data);
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+ unsigned int id);
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+ avctp_control_pdu_cb cb,
+ void *user_data);
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id);
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+ avctp_browsing_pdu_cb cb,
+ void *user_data,
+ avctp_destroy_cb_t destroy);
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+ unsigned int id);
+
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len);
+int avctp_send_vendor(struct avctp *session, uint8_t transaction,
+ uint8_t code, uint8_t subunit,
+ const struct iovec *iov, int iov_cnt);
+int avctp_send_vendor_req(struct avctp *session, uint8_t code, uint8_t subunit,
+ const struct iovec *iov, int iov_cnt,
+ avctp_rsp_cb func, void *user_data);
+int avctp_send_browsing(struct avctp *session, uint8_t transaction,
+ const struct iovec *iov, int iov_cnt);
+int avctp_send_browsing_req(struct avctp *session,
+ const struct iovec *iov, int iov_cnt,
+ avctp_browsing_rsp_cb func, void *user_data);
diff --git a/repo/android/avdtp.c b/repo/android/avdtp.c
new file mode 100644
index 0000000..bab305b
--- /dev/null
+++ b/repo/android/avdtp.c
@@ -0,0 +1,3484 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "avdtp.h"
+#include "../profiles/audio/a2dp-codecs.h"
+
+#define MAX_SEID 0x3E
+static unsigned int seids;
+
+#ifndef MAX
+# define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define AVDTP_DISCOVER 0x01
+#define AVDTP_GET_CAPABILITIES 0x02
+#define AVDTP_SET_CONFIGURATION 0x03
+#define AVDTP_GET_CONFIGURATION 0x04
+#define AVDTP_RECONFIGURE 0x05
+#define AVDTP_OPEN 0x06
+#define AVDTP_START 0x07
+#define AVDTP_CLOSE 0x08
+#define AVDTP_SUSPEND 0x09
+#define AVDTP_ABORT 0x0A
+#define AVDTP_SECURITY_CONTROL 0x0B
+#define AVDTP_GET_ALL_CAPABILITIES 0x0C
+#define AVDTP_DELAY_REPORT 0x0D
+
+#define AVDTP_PKT_TYPE_SINGLE 0x00
+#define AVDTP_PKT_TYPE_START 0x01
+#define AVDTP_PKT_TYPE_CONTINUE 0x02
+#define AVDTP_PKT_TYPE_END 0x03
+
+#define AVDTP_MSG_TYPE_COMMAND 0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT 0x01
+#define AVDTP_MSG_TYPE_ACCEPT 0x02
+#define AVDTP_MSG_TYPE_REJECT 0x03
+
+#define REQ_TIMEOUT 6
+#define ABORT_TIMEOUT 2
+#define DISCONNECT_TIMEOUT 1
+#define START_TIMEOUT 1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_common_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+} __attribute__ ((packed));
+
+struct avdtp_single_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint8_t signal_id:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint8_t no_of_packets;
+ uint8_t signal_id:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+} __attribute__ ((packed));
+
+struct seid_info {
+ uint8_t rfa0:1;
+ uint8_t inuse:1;
+ uint8_t seid:6;
+ uint8_t rfa2:3;
+ uint8_t type:1;
+ uint8_t media_type:4;
+} __attribute__ ((packed));
+
+struct seid {
+ uint8_t rfa0:2;
+ uint8_t seid:6;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_common_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+} __attribute__ ((packed));
+
+struct avdtp_single_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+ uint8_t rfa0:2;
+ uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+ uint8_t no_of_packets;
+ uint8_t rfa0:2;
+ uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+} __attribute__ ((packed));
+
+struct seid_info {
+ uint8_t seid:6;
+ uint8_t inuse:1;
+ uint8_t rfa0:1;
+ uint8_t media_type:4;
+ uint8_t type:1;
+ uint8_t rfa2:3;
+} __attribute__ ((packed));
+
+struct seid {
+ uint8_t seid:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* packets */
+
+struct discover_resp {
+ struct seid_info seps[0];
+} __attribute__ ((packed));
+
+struct getcap_resp {
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct start_req {
+ struct seid first_seid;
+ struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct suspend_req {
+ struct seid first_seid;
+ struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct seid_rej {
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct conf_rej {
+ uint8_t category;
+ uint8_t error;
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct seid_req {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+} __attribute__ ((packed));
+
+struct setconf_req {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint8_t rfa1:2;
+ uint8_t int_seid:6;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+
+ uint8_t serv_cap;
+ uint8_t serv_cap_len;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct delay_req {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint16_t delay;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct seid_req {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct setconf_req {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint8_t int_seid:6;
+ uint8_t rfa1:2;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+
+ uint8_t serv_cap;
+ uint8_t serv_cap_len;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct delay_req {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint16_t delay;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct in_buf {
+ gboolean active;
+ int no_of_packets;
+ uint8_t transaction;
+ uint8_t message_type;
+ uint8_t signal_id;
+ uint8_t buf[1024];
+ uint8_t data_size;
+};
+
+struct pending_req {
+ uint8_t transaction;
+ uint8_t signal_id;
+ void *data;
+ size_t data_size;
+ struct avdtp_stream *stream; /* Set if the request targeted a stream */
+ guint timeout;
+ gboolean collided;
+};
+
+struct avdtp_remote_sep {
+ uint8_t seid;
+ uint8_t type;
+ uint8_t media_type;
+ struct avdtp_service_capability *codec;
+ gboolean delay_reporting;
+ GSList *caps; /* of type struct avdtp_service_capability */
+ struct avdtp_stream *stream;
+};
+
+struct avdtp_local_sep {
+ avdtp_state_t state;
+ struct avdtp_stream *stream;
+ struct seid_info info;
+ uint8_t codec;
+ uint32_t vndcodec_vendor;
+ uint16_t vndcodec_codec;
+ gboolean delay_reporting;
+ GSList *caps;
+ struct avdtp_sep_ind *ind;
+ struct avdtp_sep_cfm *cfm;
+ void *user_data;
+};
+
+struct stream_callback {
+ avdtp_stream_state_cb cb;
+ void *user_data;
+ unsigned int id;
+};
+
+struct discover_callback {
+ unsigned int id;
+ avdtp_discover_cb_t cb;
+ void *user_data;
+};
+
+struct disconnect_callback {
+ unsigned int id;
+ avdtp_disconnect_cb_t cb;
+ void *user_data;
+};
+
+struct avdtp_stream {
+ GIOChannel *io;
+ uint16_t imtu;
+ uint16_t omtu;
+ struct avdtp *session;
+ struct avdtp_local_sep *lsep;
+ uint8_t rseid;
+ GSList *caps;
+ GSList *callbacks;
+ struct avdtp_service_capability *codec;
+ guint io_id; /* Transport GSource ID */
+ guint timer; /* Waiting for other side to close or open
+ * the transport channel */
+ gboolean open_acp; /* If we are in ACT role for Open */
+ gboolean close_int; /* If we are in INT role for Close */
+ gboolean abort_int; /* If we are in INT role for Abort */
+ guint start_timer; /* Wait START command timer */
+ gboolean delay_reporting;
+ uint16_t delay; /* AVDTP 1.3 Delay Reporting feature */
+ gboolean starting; /* only valid while sep state == OPEN */
+};
+
+/* Structure describing an AVDTP connection between two devices */
+
+struct avdtp {
+ unsigned int ref;
+
+ uint16_t version;
+
+ guint auth_id;
+
+ GIOChannel *io;
+ guint io_id;
+
+ GSList *seps; /* Elements of type struct avdtp_remote_sep * */
+ struct queue *lseps; /* Elements of type struct avdtp_local_sep * */
+
+ GSList *streams; /* Elements of type struct avdtp_stream * */
+
+ GSList *req_queue; /* Elements of type struct pending_req * */
+ GSList *prio_queue; /* Same as req_queue but is processed before it */
+
+ struct avdtp_stream *pending_open;
+
+ uint16_t imtu;
+ uint16_t omtu;
+
+ struct in_buf in;
+
+ char *buf;
+
+ struct discover_callback *discover;
+ struct pending_req *req;
+
+ GSList *disconnect;
+
+ bool shutdown;
+};
+
+static int send_request(struct avdtp *session, gboolean priority,
+ struct avdtp_stream *stream, uint8_t signal_id,
+ void *buffer, size_t size);
+static gboolean avdtp_parse_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ uint8_t transaction, uint8_t signal_id,
+ void *buf, int size);
+static gboolean avdtp_parse_rej(struct avdtp *session,
+ struct avdtp_stream *stream,
+ uint8_t transaction, uint8_t signal_id,
+ void *buf, int size);
+static int process_queue(struct avdtp *session);
+static void avdtp_sep_set_state(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ avdtp_state_t state);
+
+static const char *avdtp_statestr(avdtp_state_t state)
+{
+ switch (state) {
+ case AVDTP_STATE_IDLE:
+ return "IDLE";
+ case AVDTP_STATE_CONFIGURED:
+ return "CONFIGURED";
+ case AVDTP_STATE_OPEN:
+ return "OPEN";
+ case AVDTP_STATE_STREAMING:
+ return "STREAMING";
+ case AVDTP_STATE_CLOSING:
+ return "CLOSING";
+ case AVDTP_STATE_ABORTING:
+ return "ABORTING";
+ default:
+ return "<unknown state>";
+ }
+}
+
+static gboolean try_send(int sk, void *data, size_t len)
+{
+ int err;
+
+ do {
+ err = send(sk, data, len, 0);
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ error("send: %s (%d)", strerror(errno), errno);
+ return FALSE;
+ } else if ((size_t) err != len) {
+ error("try_send: complete buffer not sent (%d/%zu bytes)",
+ err, len);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
+ uint8_t message_type, uint8_t signal_id,
+ void *data, size_t len)
+{
+ unsigned int cont_fragments, sent;
+ struct avdtp_start_header start;
+ struct avdtp_continue_header cont;
+ int sock;
+
+ if (session->io == NULL) {
+ error("avdtp_send: session is closed");
+ return FALSE;
+ }
+
+ sock = g_io_channel_unix_get_fd(session->io);
+
+ /* Single packet - no fragmentation */
+ if (sizeof(struct avdtp_single_header) + len <= session->omtu) {
+ struct avdtp_single_header single;
+
+ memset(&single, 0, sizeof(single));
+
+ single.transaction = transaction;
+ single.packet_type = AVDTP_PKT_TYPE_SINGLE;
+ single.message_type = message_type;
+ single.signal_id = signal_id;
+
+ memcpy(session->buf, &single, sizeof(single));
+ memcpy(session->buf + sizeof(single), data, len);
+
+ return try_send(sock, session->buf, sizeof(single) + len);
+ }
+
+ /* Check if there is enough space to start packet */
+ if (session->omtu < sizeof(start)) {
+ error("No enough space to fragment packet");
+ return FALSE;
+ }
+
+ /* Count the number of needed fragments */
+ cont_fragments = (len - (session->omtu - sizeof(start))) /
+ (session->omtu - sizeof(cont)) + 1;
+
+ DBG("%zu bytes split into %d fragments", len, cont_fragments + 1);
+
+ /* Send the start packet */
+ memset(&start, 0, sizeof(start));
+ start.transaction = transaction;
+ start.packet_type = AVDTP_PKT_TYPE_START;
+ start.message_type = message_type;
+ start.no_of_packets = cont_fragments + 1;
+ start.signal_id = signal_id;
+
+ memcpy(session->buf, &start, sizeof(start));
+ memcpy(session->buf + sizeof(start), data,
+ session->omtu - sizeof(start));
+
+ if (!try_send(sock, session->buf, session->omtu))
+ return FALSE;
+
+ DBG("first packet with %zu bytes sent", session->omtu - sizeof(start));
+
+ sent = session->omtu - sizeof(start);
+
+ /* Send the continue fragments and the end packet */
+ while (sent < len) {
+ int left, to_copy;
+
+ left = len - sent;
+ if (left + sizeof(cont) > session->omtu) {
+ cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
+ to_copy = session->omtu - sizeof(cont);
+ DBG("sending continue with %d bytes", to_copy);
+ } else {
+ cont.packet_type = AVDTP_PKT_TYPE_END;
+ to_copy = left;
+ DBG("sending end with %d bytes", to_copy);
+ }
+
+ cont.transaction = transaction;
+ cont.message_type = message_type;
+
+ memcpy(session->buf, &cont, sizeof(cont));
+ memcpy(session->buf + sizeof(cont), data + sent, to_copy);
+
+ if (!try_send(sock, session->buf, to_copy + sizeof(cont)))
+ return FALSE;
+
+ sent += to_copy;
+ }
+
+ return TRUE;
+}
+
+static void pending_req_free(void *data)
+{
+ struct pending_req *req = data;
+
+ if (req->timeout)
+ g_source_remove(req->timeout);
+ g_free(req->data);
+ g_free(req);
+}
+
+static void close_stream(struct avdtp_stream *stream)
+{
+ int sock;
+
+ if (stream->io == NULL)
+ return;
+
+ sock = g_io_channel_unix_get_fd(stream->io);
+
+ shutdown(sock, SHUT_RDWR);
+
+ g_io_channel_shutdown(stream->io, FALSE, NULL);
+
+ g_io_channel_unref(stream->io);
+ stream->io = NULL;
+}
+
+static gboolean stream_close_timeout(gpointer user_data)
+{
+ struct avdtp_stream *stream = user_data;
+
+ DBG("Timed out waiting for peer to close the transport channel");
+
+ stream->timer = 0;
+
+ close_stream(stream);
+
+ return FALSE;
+}
+
+static gboolean stream_open_timeout(gpointer user_data)
+{
+ struct avdtp_stream *stream = user_data;
+
+ DBG("Timed out waiting for peer to open the transport channel");
+
+ stream->timer = 0;
+
+ stream->session->pending_open = NULL;
+
+ avdtp_abort(stream->session, stream);
+
+ return FALSE;
+}
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t category, int id)
+{
+ err->category = category;
+
+ if (category == AVDTP_ERRNO)
+ err->err.posix_errno = id;
+ else
+ err->err.error_code = id;
+}
+
+uint8_t avdtp_error_category(struct avdtp_error *err)
+{
+ return err->category;
+}
+
+int avdtp_error_error_code(struct avdtp_error *err)
+{
+ assert(err->category != AVDTP_ERRNO);
+ return err->err.error_code;
+}
+
+int avdtp_error_posix_errno(struct avdtp_error *err)
+{
+ assert(err->category == AVDTP_ERRNO);
+ return err->err.posix_errno;
+}
+
+static struct avdtp_stream *find_stream_by_rseid(struct avdtp *session,
+ uint8_t rseid)
+{
+ GSList *l;
+
+ for (l = session->streams; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_stream *stream = l->data;
+
+ if (stream->rseid == rseid)
+ return stream;
+ }
+
+ return NULL;
+}
+
+static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid)
+{
+ GSList *l;
+
+ for (l = seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_remote_sep *sep = l->data;
+
+ if (sep->seid == seid)
+ return sep;
+ }
+
+ return NULL;
+}
+
+static void stream_free(void *data)
+{
+ struct avdtp_stream *stream = data;
+ struct avdtp_remote_sep *rsep;
+
+ stream->lsep->info.inuse = 0;
+ stream->lsep->stream = NULL;
+
+ rsep = find_remote_sep(stream->session->seps, stream->rseid);
+ if (rsep)
+ rsep->stream = NULL;
+
+ if (stream->timer)
+ g_source_remove(stream->timer);
+
+ if (stream->start_timer > 0)
+ g_source_remove(stream->start_timer);
+
+ if (stream->io)
+ close_stream(stream);
+
+ if (stream->io_id)
+ g_source_remove(stream->io_id);
+
+ g_slist_free_full(stream->callbacks, g_free);
+ g_slist_free_full(stream->caps, g_free);
+
+ g_free(stream);
+}
+
+static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avdtp_stream *stream = data;
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (stream->close_int && sep->cfm && sep->cfm->close)
+ sep->cfm->close(stream->session, sep, stream, NULL,
+ sep->user_data);
+
+ if (!(cond & G_IO_NVAL))
+ close_stream(stream);
+
+ stream->io_id = 0;
+
+ if (!stream->abort_int)
+ avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE);
+
+ return FALSE;
+}
+
+static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
+ uint16_t imtu, uint16_t omtu)
+{
+ struct avdtp_stream *stream = session->pending_open;
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ session->pending_open = NULL;
+
+ if (stream->timer) {
+ g_source_remove(stream->timer);
+ stream->timer = 0;
+ }
+
+ if (io == NULL)
+ return;
+
+ if (stream->io == NULL)
+ stream->io = g_io_channel_ref(io);
+
+ stream->omtu = omtu;
+ stream->imtu = imtu;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+ stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) transport_cb, stream);
+}
+
+static int pending_req_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct pending_req *req = a;
+ const struct avdtp_stream *stream = b;
+
+ if (req->stream == stream)
+ return 0;
+
+ return -1;
+}
+
+static void cleanup_queue(struct avdtp *session, struct avdtp_stream *stream)
+{
+ GSList *l;
+ struct pending_req *req;
+
+ while ((l = g_slist_find_custom(session->prio_queue, stream,
+ pending_req_cmp))) {
+ req = l->data;
+ pending_req_free(req);
+ session->prio_queue = g_slist_remove(session->prio_queue, req);
+ }
+
+ while ((l = g_slist_find_custom(session->req_queue, stream,
+ pending_req_cmp))) {
+ req = l->data;
+ pending_req_free(req);
+ session->req_queue = g_slist_remove(session->req_queue, req);
+ }
+}
+
+static void handle_unanswered_req(struct avdtp *session,
+ struct avdtp_stream *stream)
+{
+ struct pending_req *req;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_error err;
+
+ if (!session->req->timeout)
+ /* Request is in process */
+ return;
+
+ if (session->req->signal_id == AVDTP_ABORT) {
+ /* Avoid freeing the Abort request here */
+ DBG("handle_unanswered_req: Abort req, returning");
+ session->req->stream = NULL;
+ return;
+ }
+
+ req = session->req;
+ session->req = NULL;
+
+ avdtp_error_init(&err, AVDTP_ERRNO, EIO);
+
+ lsep = stream->lsep;
+
+ switch (req->signal_id) {
+ case AVDTP_RECONFIGURE:
+ error("No reply to Reconfigure request");
+ if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+ lsep->cfm->reconfigure(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_OPEN:
+ error("No reply to Open request");
+ if (lsep && lsep->cfm && lsep->cfm->open)
+ lsep->cfm->open(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_START:
+ error("No reply to Start request");
+ if (lsep && lsep->cfm && lsep->cfm->start)
+ lsep->cfm->start(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SUSPEND:
+ error("No reply to Suspend request");
+ if (lsep && lsep->cfm && lsep->cfm->suspend)
+ lsep->cfm->suspend(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_CLOSE:
+ error("No reply to Close request");
+ if (lsep && lsep->cfm && lsep->cfm->close)
+ lsep->cfm->close(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SET_CONFIGURATION:
+ error("No reply to SetConfiguration request");
+ if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+ lsep->cfm->set_configuration(session, lsep, stream,
+ &err, lsep->user_data);
+ }
+
+ pending_req_free(req);
+}
+
+static void avdtp_sep_set_state(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ avdtp_state_t state)
+{
+ struct avdtp_stream *stream = sep->stream;
+ avdtp_state_t old_state;
+ struct avdtp_error err, *err_ptr = NULL;
+ GSList *l;
+
+ if (!stream) {
+ error("Error changing sep state: stream not available");
+ return;
+ }
+
+ if (sep->state == state) {
+ avdtp_error_init(&err, AVDTP_ERRNO, EIO);
+ DBG("stream state change failed: %s", avdtp_strerror(&err));
+ err_ptr = &err;
+ } else {
+ err_ptr = NULL;
+ DBG("stream state changed: %s -> %s",
+ avdtp_statestr(sep->state),
+ avdtp_statestr(state));
+ }
+
+ old_state = sep->state;
+ sep->state = state;
+
+ switch (state) {
+ case AVDTP_STATE_CONFIGURED:
+ if (sep->info.type == AVDTP_SEP_TYPE_SINK)
+ avdtp_delay_report(session, stream, stream->delay);
+ break;
+ case AVDTP_STATE_OPEN:
+ stream->starting = FALSE;
+ break;
+ case AVDTP_STATE_STREAMING:
+ if (stream->start_timer) {
+ g_source_remove(stream->start_timer);
+ stream->start_timer = 0;
+ }
+ stream->open_acp = FALSE;
+ break;
+ case AVDTP_STATE_CLOSING:
+ case AVDTP_STATE_ABORTING:
+ if (stream->start_timer) {
+ g_source_remove(stream->start_timer);
+ stream->start_timer = 0;
+ }
+ break;
+ case AVDTP_STATE_IDLE:
+ if (stream->start_timer) {
+ g_source_remove(stream->start_timer);
+ stream->start_timer = 0;
+ }
+ if (session->pending_open == stream)
+ handle_transport_connect(session, NULL, 0, 0);
+ if (session->req && session->req->stream == stream)
+ handle_unanswered_req(session, stream);
+ /* Remove pending commands for this stream from the queue */
+ cleanup_queue(session, stream);
+ break;
+ default:
+ break;
+ }
+
+ l = stream->callbacks;
+ while (l != NULL) {
+ struct stream_callback *cb = l->data;
+ l = g_slist_next(l);
+ cb->cb(stream, old_state, state, err_ptr, cb->user_data);
+ }
+
+ if (state == AVDTP_STATE_IDLE &&
+ g_slist_find(session->streams, stream)) {
+ session->streams = g_slist_remove(session->streams, stream);
+ stream_free(stream);
+ }
+
+ if (session->io && session->shutdown && session->streams == NULL) {
+ int sock = g_io_channel_unix_get_fd(session->io);
+ shutdown(sock, SHUT_RDWR);
+ }
+}
+
+static void finalize_discovery(struct avdtp *session, int err)
+{
+ struct discover_callback *discover = session->discover;
+ struct avdtp_error avdtp_err;
+
+ if (!discover)
+ return;
+
+ session->discover = NULL;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
+
+ if (discover->id > 0)
+ g_source_remove(discover->id);
+
+ if (discover->cb)
+ discover->cb(session, session->seps, err ? &avdtp_err : NULL,
+ discover->user_data);
+ g_free(discover);
+}
+
+static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->abort &&
+ (sep->state != AVDTP_STATE_ABORTING ||
+ stream->abort_int))
+ sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+}
+
+static void sep_free(gpointer data)
+{
+ struct avdtp_remote_sep *sep = data;
+
+ g_slist_free_full(sep->caps, g_free);
+ g_free(sep);
+}
+
+static void avdtp_free(void *data)
+{
+ struct avdtp *session = data;
+
+ DBG("%p", session);
+
+ g_slist_free_full(session->streams, stream_free);
+
+ if (session->io) {
+ g_io_channel_shutdown(session->io, FALSE, NULL);
+ g_io_channel_unref(session->io);
+ }
+
+ if (session->io_id) {
+ g_source_remove(session->io_id);
+ session->io_id = 0;
+ }
+
+ if (session->req)
+ pending_req_free(session->req);
+
+ g_slist_free_full(session->req_queue, pending_req_free);
+ g_slist_free_full(session->prio_queue, pending_req_free);
+ g_slist_free_full(session->seps, sep_free);
+ g_slist_free_full(session->disconnect, g_free);
+
+ /* Free copy of the SEP list */
+ session->lseps = NULL;
+
+ g_free(session->buf);
+
+ g_free(session);
+}
+
+static void process_disconnect(void *data)
+{
+ struct disconnect_callback *callback = data;
+
+ callback->cb(callback->user_data);
+
+ g_free(callback);
+}
+
+static void connection_lost(struct avdtp *session, int err)
+{
+ DBG("Disconnected: %s (%d)", strerror(err), err);
+
+ g_slist_foreach(session->streams, (GFunc) release_stream, session);
+ session->streams = NULL;
+
+ avdtp_ref(session);
+
+ finalize_discovery(session, err);
+
+ g_slist_free_full(session->disconnect, process_disconnect);
+ session->disconnect = NULL;
+
+ avdtp_unref(session);
+}
+
+void avdtp_unref(struct avdtp *session)
+{
+ if (!session)
+ return;
+
+ session->ref--;
+
+ DBG("%p: ref=%d", session, session->ref);
+
+ if (session->ref > 0)
+ return;
+
+ finalize_discovery(session, ECONNABORTED);
+
+ avdtp_free(session);
+}
+
+struct avdtp *avdtp_ref(struct avdtp *session)
+{
+ session->ref++;
+
+ DBG("%p: ref=%d", session, session->ref);
+
+ return session;
+}
+
+static bool match_by_seid(const void *data, const void *user_data)
+{
+ const struct avdtp_local_sep *sep = data;
+ uint8_t seid = PTR_TO_UINT(user_data);
+
+ return sep->info.seid == seid;
+}
+
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp *session,
+ uint8_t seid)
+{
+ return queue_find(session->lseps, match_by_seid, INT_TO_PTR(seid));
+}
+
+struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
+ struct avdtp_local_sep *lsep)
+{
+ GSList *l;
+
+ if (lsep->info.inuse)
+ return NULL;
+
+ for (l = session->seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_remote_sep *sep = l->data;
+ struct avdtp_service_capability *cap;
+ struct avdtp_media_codec_capability *codec_data;
+
+ /* Type must be different: source <-> sink */
+ if (sep->type == lsep->info.type)
+ continue;
+
+ if (sep->media_type != lsep->info.media_type)
+ continue;
+
+ if (!sep->codec)
+ continue;
+
+ cap = sep->codec;
+ codec_data = (void *) cap->data;
+
+ if (codec_data->media_codec_type != lsep->codec)
+ continue;
+
+ /* FIXME: Add Vendor Specific Codec match to SEP callback */
+ if (lsep->codec == A2DP_CODEC_VENDOR) {
+ a2dp_vendor_codec_t *vndcodec =
+ (void *) codec_data->data;
+
+ if (btohl(vndcodec->vendor_id) != lsep->vndcodec_vendor)
+ continue;
+
+ if (btohs(vndcodec->codec_id) != lsep->vndcodec_codec)
+ continue;
+ }
+
+ if (sep->stream == NULL)
+ return sep;
+ }
+
+ return NULL;
+}
+
+static GSList *caps_to_list(uint8_t *data, int size,
+ struct avdtp_service_capability **codec,
+ gboolean *delay_reporting)
+{
+ GSList *caps;
+ int processed;
+
+ if (delay_reporting)
+ *delay_reporting = FALSE;
+
+ for (processed = 0, caps = NULL; processed + 2 <= size;) {
+ struct avdtp_service_capability *cap;
+ uint8_t length, category;
+
+ category = data[0];
+ length = data[1];
+
+ if (processed + 2 + length > size) {
+ error("Invalid capability data in getcap resp");
+ break;
+ }
+
+ cap = g_malloc(sizeof(struct avdtp_service_capability) +
+ length);
+ memcpy(cap, data, 2 + length);
+
+ processed += 2 + length;
+ data += 2 + length;
+
+ caps = g_slist_append(caps, cap);
+
+ if (category == AVDTP_MEDIA_CODEC &&
+ length >=
+ sizeof(struct avdtp_media_codec_capability))
+ *codec = cap;
+ else if (category == AVDTP_DELAY_REPORTING && delay_reporting)
+ *delay_reporting = TRUE;
+ }
+
+ return caps;
+}
+
+static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
+ uint8_t signal_id)
+{
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_GEN_REJECT,
+ signal_id, NULL, 0);
+}
+
+static void copy_seps(void *data, void *user_data)
+{
+ struct avdtp_local_sep *sep = data;
+ struct seid_info **p = user_data;
+
+ memcpy(*p, &sep->info, sizeof(struct seid_info));
+ *p = *p + 1;
+}
+
+static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
+ void *buf, int size)
+{
+ unsigned int rsp_size, sep_count;
+ struct seid_info *seps, *p;
+ gboolean ret;
+
+ sep_count = queue_length(session->lseps);
+
+ if (sep_count == 0) {
+ uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_DISCOVER, &err, sizeof(err));
+ }
+
+ rsp_size = sep_count * sizeof(struct seid_info);
+
+ seps = g_new0(struct seid_info, sep_count);
+ p = seps;
+
+ queue_foreach(session->lseps, copy_seps, &p);
+
+ ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_DISCOVER, seps, rsp_size);
+ g_free(seps);
+
+ return ret;
+}
+
+static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, unsigned int size,
+ gboolean get_all)
+{
+ GSList *l, *caps;
+ struct avdtp_local_sep *sep = NULL;
+ unsigned int rsp_size;
+ uint8_t err, buf[1024], *ptr = buf;
+ uint8_t cmd;
+
+ cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES;
+
+ if (size < sizeof(struct seid_req)) {
+ err = AVDTP_BAD_LENGTH;
+ goto failed;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (!sep->ind->get_capability(session, sep, &caps, &err,
+ sep->user_data))
+ goto failed;
+
+ for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (rsp_size + cap->length + 2 > sizeof(buf))
+ break;
+
+ memcpy(ptr, cap, cap->length + 2);
+ rsp_size += cap->length + 2;
+ ptr += cap->length + 2;
+
+ g_free(cap);
+ }
+
+ if (get_all && sep->delay_reporting) {
+ ptr[0] = AVDTP_DELAY_REPORTING;
+ ptr[1] = 0x00;
+ rsp_size += 2;
+ }
+
+ g_slist_free(caps);
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd,
+ buf, rsp_size);
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd,
+ &err, sizeof(err));
+}
+
+static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream,
+ struct avdtp_error *err)
+{
+ struct conf_rej rej;
+ struct avdtp_local_sep *sep;
+
+ if (err != NULL) {
+ rej.error = AVDTP_UNSUPPORTED_CONFIGURATION;
+ rej.category = err->err.error_code;
+ avdtp_send(session, session->in.transaction,
+ AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION,
+ &rej, sizeof(rej));
+ return;
+ }
+
+ if (!avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_SET_CONFIGURATION, NULL, 0)) {
+ stream_free(stream);
+ return;
+ }
+
+ sep = stream->lsep;
+ sep->stream = stream;
+ sep->info.inuse = 1;
+ session->streams = g_slist_append(session->streams, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+}
+
+static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
+ struct setconf_req *req, unsigned int size)
+{
+ struct conf_rej rej;
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err, category = 0x00;
+ GSList *l;
+
+ if (size < sizeof(struct setconf_req)) {
+ error("Too short getcap request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->stream) {
+ err = AVDTP_SEP_IN_USE;
+ goto failed;
+ }
+
+ stream = g_new0(struct avdtp_stream, 1);
+ stream->session = session;
+ stream->lsep = sep;
+ stream->rseid = req->int_seid;
+ stream->caps = caps_to_list(req->caps,
+ size - sizeof(struct setconf_req),
+ &stream->codec,
+ &stream->delay_reporting);
+
+ /*
+ * Verify that the Media Transport capability's length = 0.
+ * Reject otherwise
+ */
+ for (l = stream->caps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (cap->category == AVDTP_MEDIA_TRANSPORT &&
+ cap->length != 0) {
+ err = AVDTP_BAD_MEDIA_TRANSPORT_FORMAT;
+ goto failed_stream;
+ }
+ }
+
+ if (stream->delay_reporting && session->version < 0x0103)
+ session->version = 0x0103;
+
+ if (sep->ind && sep->ind->set_configuration) {
+ if (!sep->ind->set_configuration(session, sep, stream,
+ stream->caps,
+ setconf_cb,
+ sep->user_data)) {
+ err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ category = 0x00;
+ goto failed_stream;
+ }
+ } else {
+ if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_SET_CONFIGURATION, NULL, 0)) {
+ stream_free(stream);
+ return FALSE;
+ }
+
+ sep->stream = stream;
+ sep->info.inuse = 1;
+ session->streams = g_slist_append(session->streams, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+ }
+
+ return TRUE;
+
+failed_stream:
+ stream_free(stream);
+failed:
+ rej.error = err;
+ rej.category = category;
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_SET_CONFIGURATION, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, int size)
+{
+ GSList *l;
+ struct avdtp_local_sep *sep = NULL;
+ int rsp_size;
+ uint8_t err;
+ uint8_t buf[1024];
+ uint8_t *ptr = buf;
+
+ if (size < (int) sizeof(struct seid_req)) {
+ error("Too short getconf request");
+ return FALSE;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+ if (!sep->stream || !sep->stream->caps) {
+ err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ goto failed;
+ }
+
+ for (l = sep->stream->caps, rsp_size = 0; l; l = g_slist_next(l)) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (rsp_size + cap->length + 2 > (int) sizeof(buf))
+ break;
+
+ memcpy(ptr, cap, cap->length + 2);
+ rsp_size += cap->length + 2;
+ ptr += cap->length + 2;
+ }
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_GET_CONFIGURATION, buf, rsp_size);
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_GET_CONFIGURATION, &err, sizeof(err));
+}
+
+static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, int size)
+{
+ struct conf_rej rej;
+
+ rej.error = AVDTP_NOT_SUPPORTED_COMMAND;
+ rej.category = 0x00;
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_RECONFIGURE, &rej, sizeof(rej));
+}
+
+static void check_seid_collision(struct pending_req *req, uint8_t id)
+{
+ struct seid_req *seid = req->data;
+
+ if (seid->acp_seid == id)
+ req->collided = TRUE;
+}
+
+static void check_start_collision(struct pending_req *req, uint8_t id)
+{
+ struct start_req *start = req->data;
+ struct seid *seid = &start->first_seid;
+ int count = 1 + req->data_size - sizeof(struct start_req);
+ int i;
+
+ for (i = 0; i < count; i++, seid++) {
+ if (seid->seid == id) {
+ req->collided = TRUE;
+ return;
+ }
+ }
+}
+
+static void check_suspend_collision(struct pending_req *req, uint8_t id)
+{
+ struct suspend_req *suspend = req->data;
+ struct seid *seid = &suspend->first_seid;
+ int count = 1 + req->data_size - sizeof(struct suspend_req);
+ int i;
+
+ for (i = 0; i < count; i++, seid++) {
+ if (seid->seid == id) {
+ req->collided = TRUE;
+ return;
+ }
+ }
+}
+
+static void avdtp_check_collision(struct avdtp *session, uint8_t cmd,
+ struct avdtp_stream *stream)
+{
+ struct pending_req *req = session->req;
+
+ if (req == NULL || (req->signal_id != cmd && cmd != AVDTP_ABORT))
+ return;
+
+ if (cmd == AVDTP_ABORT)
+ cmd = req->signal_id;
+
+ switch (cmd) {
+ case AVDTP_OPEN:
+ case AVDTP_CLOSE:
+ check_seid_collision(req, stream->rseid);
+ break;
+ case AVDTP_START:
+ check_start_collision(req, stream->rseid);
+ break;
+ case AVDTP_SUSPEND:
+ check_suspend_collision(req, stream->rseid);
+ break;
+ }
+}
+
+static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short abort request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->state != AVDTP_STATE_CONFIGURED) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->ind && sep->ind->open) {
+ if (!sep->ind->open(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_check_collision(session, AVDTP_OPEN, stream);
+
+ if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_OPEN, NULL, 0))
+ return FALSE;
+
+ stream->open_acp = TRUE;
+ session->pending_open = stream;
+ stream->timer = g_timeout_add_seconds(REQ_TIMEOUT,
+ stream_open_timeout,
+ stream);
+
+ return TRUE;
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_OPEN, &err, sizeof(err));
+}
+
+static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
+ struct start_req *req, unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct stream_rej rej;
+ struct seid *seid;
+ uint8_t err, failed_seid;
+ int seid_count, i;
+
+ if (size < sizeof(struct start_req)) {
+ error("Too short start request");
+ return FALSE;
+ }
+
+ seid_count = 1 + size - sizeof(struct start_req);
+
+ seid = &req->first_seid;
+
+ for (i = 0; i < seid_count; i++, seid++) {
+ failed_seid = seid->seid;
+
+ sep = find_local_sep_by_seid(session, seid->seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ /* Also reject start cmd if state is not open */
+ if (sep->state != AVDTP_STATE_OPEN) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+ stream->starting = TRUE;
+
+ if (sep->ind && sep->ind->start) {
+ if (!sep->ind->start(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_check_collision(session, AVDTP_START, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+ }
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_START, NULL, 0);
+
+failed:
+ DBG("Rejecting (%d)", err);
+ memset(&rej, 0, sizeof(rej));
+ rej.acp_seid = failed_seid;
+ rej.error = err;
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_START, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short close request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->state != AVDTP_STATE_OPEN &&
+ sep->state != AVDTP_STATE_STREAMING) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->ind && sep->ind->close) {
+ if (!sep->ind->close(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_check_collision(session, AVDTP_CLOSE, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+ if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_CLOSE, NULL, 0))
+ return FALSE;
+
+ stream->timer = g_timeout_add_seconds(REQ_TIMEOUT,
+ stream_close_timeout,
+ stream);
+
+ return TRUE;
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_CLOSE, &err, sizeof(err));
+}
+
+static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
+ struct suspend_req *req, unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct stream_rej rej;
+ struct seid *seid;
+ uint8_t err, failed_seid;
+ int seid_count, i;
+
+ if (size < sizeof(struct suspend_req)) {
+ error("Too short suspend request");
+ return FALSE;
+ }
+
+ seid_count = 1 + size - sizeof(struct suspend_req);
+
+ seid = &req->first_seid;
+
+ for (i = 0; i < seid_count; i++, seid++) {
+ failed_seid = seid->seid;
+
+ sep = find_local_sep_by_seid(session, seid->seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->state != AVDTP_STATE_STREAMING) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ if (sep->ind && sep->ind->suspend) {
+ if (!sep->ind->suspend(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_check_collision(session, AVDTP_SUSPEND, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+ }
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_SUSPEND, NULL, 0);
+
+failed:
+ memset(&rej, 0, sizeof(rej));
+ rej.acp_seid = failed_seid;
+ rej.error = err;
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_SUSPEND, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ uint8_t err;
+ gboolean ret;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short abort request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep || !sep->stream)
+ return TRUE;
+
+ if (sep->ind && sep->ind->abort)
+ sep->ind->abort(session, sep, sep->stream, &err,
+ sep->user_data);
+
+ avdtp_check_collision(session, AVDTP_ABORT, sep->stream);
+
+ ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_ABORT, NULL, 0);
+ if (ret)
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
+
+ return ret;
+}
+
+static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction,
+ struct seid_req *req, int size)
+{
+ return avdtp_unknown_cmd(session, transaction, AVDTP_SECURITY_CONTROL);
+}
+
+static gboolean avdtp_delayreport_cmd(struct avdtp *session,
+ uint8_t transaction,
+ struct delay_req *req,
+ unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err;
+
+ if (size < sizeof(struct delay_req)) {
+ error("Too short delay report request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session, req->acp_seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ switch (sep->state) {
+ case AVDTP_STATE_IDLE:
+ case AVDTP_STATE_ABORTING:
+ case AVDTP_STATE_CLOSING:
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ case AVDTP_STATE_CONFIGURED:
+ case AVDTP_STATE_OPEN:
+ case AVDTP_STATE_STREAMING:
+ default:
+ break;
+ }
+
+ stream->delay = ntohs(req->delay);
+
+ if (sep->ind && sep->ind->delayreport) {
+ if (!sep->ind->delayreport(session, sep, stream->rseid,
+ stream->delay, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_DELAY_REPORT, NULL, 0);
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_DELAY_REPORT, &err, sizeof(err));
+}
+
+static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction,
+ uint8_t signal_id, void *buf, int size)
+{
+ switch (signal_id) {
+ case AVDTP_DISCOVER:
+ DBG("Received DISCOVER_CMD");
+ return avdtp_discover_cmd(session, transaction, buf, size);
+ case AVDTP_GET_CAPABILITIES:
+ DBG("Received GET_CAPABILITIES_CMD");
+ return avdtp_getcap_cmd(session, transaction, buf, size,
+ FALSE);
+ case AVDTP_GET_ALL_CAPABILITIES:
+ DBG("Received GET_ALL_CAPABILITIES_CMD");
+ return avdtp_getcap_cmd(session, transaction, buf, size, TRUE);
+ case AVDTP_SET_CONFIGURATION:
+ DBG("Received SET_CONFIGURATION_CMD");
+ return avdtp_setconf_cmd(session, transaction, buf, size);
+ case AVDTP_GET_CONFIGURATION:
+ DBG("Received GET_CONFIGURATION_CMD");
+ return avdtp_getconf_cmd(session, transaction, buf, size);
+ case AVDTP_RECONFIGURE:
+ DBG("Received RECONFIGURE_CMD");
+ return avdtp_reconf_cmd(session, transaction, buf, size);
+ case AVDTP_OPEN:
+ DBG("Received OPEN_CMD");
+ return avdtp_open_cmd(session, transaction, buf, size);
+ case AVDTP_START:
+ DBG("Received START_CMD");
+ return avdtp_start_cmd(session, transaction, buf, size);
+ case AVDTP_CLOSE:
+ DBG("Received CLOSE_CMD");
+ return avdtp_close_cmd(session, transaction, buf, size);
+ case AVDTP_SUSPEND:
+ DBG("Received SUSPEND_CMD");
+ return avdtp_suspend_cmd(session, transaction, buf, size);
+ case AVDTP_ABORT:
+ DBG("Received ABORT_CMD");
+ return avdtp_abort_cmd(session, transaction, buf, size);
+ case AVDTP_SECURITY_CONTROL:
+ DBG("Received SECURITY_CONTROL_CMD");
+ return avdtp_secctl_cmd(session, transaction, buf, size);
+ case AVDTP_DELAY_REPORT:
+ DBG("Received DELAY_REPORT_CMD");
+ return avdtp_delayreport_cmd(session, transaction, buf, size);
+ default:
+ DBG("Received unknown request id %u", signal_id);
+ return avdtp_unknown_cmd(session, transaction, signal_id);
+ }
+}
+
+enum avdtp_parse_result { PARSE_ERROR, PARSE_FRAGMENT, PARSE_SUCCESS };
+
+static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session,
+ void *buf, size_t size)
+{
+ struct avdtp_common_header *header = buf;
+ struct avdtp_single_header *single = (void *) session->buf;
+ struct avdtp_start_header *start = (void *) session->buf;
+ void *payload;
+ gsize payload_size;
+
+ switch (header->packet_type) {
+ case AVDTP_PKT_TYPE_SINGLE:
+ if (size < sizeof(*single)) {
+ error("Received too small single packet (%zu bytes)",
+ size);
+ return PARSE_ERROR;
+ }
+ if (session->in.active) {
+ error("SINGLE: Invalid AVDTP packet fragmentation");
+ return PARSE_ERROR;
+ }
+
+ payload = session->buf + sizeof(*single);
+ payload_size = size - sizeof(*single);
+
+ session->in.active = TRUE;
+ session->in.data_size = 0;
+ session->in.no_of_packets = 1;
+ session->in.transaction = header->transaction;
+ session->in.message_type = header->message_type;
+ session->in.signal_id = single->signal_id;
+
+ break;
+ case AVDTP_PKT_TYPE_START:
+ if (size < sizeof(*start)) {
+ error("Received too small start packet (%zu bytes)",
+ size);
+ return PARSE_ERROR;
+ }
+ if (session->in.active) {
+ error("START: Invalid AVDTP packet fragmentation");
+ return PARSE_ERROR;
+ }
+
+ session->in.active = TRUE;
+ session->in.data_size = 0;
+ session->in.transaction = header->transaction;
+ session->in.message_type = header->message_type;
+ session->in.no_of_packets = start->no_of_packets;
+ session->in.signal_id = start->signal_id;
+
+ payload = session->buf + sizeof(*start);
+ payload_size = size - sizeof(*start);
+
+ break;
+ case AVDTP_PKT_TYPE_CONTINUE:
+ if (size < sizeof(struct avdtp_continue_header)) {
+ error("Received too small continue packet (%zu bytes)",
+ size);
+ return PARSE_ERROR;
+ }
+ if (!session->in.active) {
+ error("CONTINUE: Invalid AVDTP packet fragmentation");
+ return PARSE_ERROR;
+ }
+ if (session->in.transaction != header->transaction) {
+ error("Continue transaction id doesn't match");
+ return PARSE_ERROR;
+ }
+ if (session->in.no_of_packets <= 1) {
+ error("Too few continue packets");
+ return PARSE_ERROR;
+ }
+
+ payload = session->buf + sizeof(struct avdtp_continue_header);
+ payload_size = size - sizeof(struct avdtp_continue_header);
+
+ break;
+ case AVDTP_PKT_TYPE_END:
+ if (size < sizeof(struct avdtp_continue_header)) {
+ error("Received too small end packet (%zu bytes)",
+ size);
+ return PARSE_ERROR;
+ }
+ if (!session->in.active) {
+ error("END: Invalid AVDTP packet fragmentation");
+ return PARSE_ERROR;
+ }
+ if (session->in.transaction != header->transaction) {
+ error("End transaction id doesn't match");
+ return PARSE_ERROR;
+ }
+ if (session->in.no_of_packets > 1) {
+ error("Got an end packet too early");
+ return PARSE_ERROR;
+ }
+
+ payload = session->buf + sizeof(struct avdtp_continue_header);
+ payload_size = size - sizeof(struct avdtp_continue_header);
+
+ break;
+ default:
+ error("Invalid AVDTP packet type 0x%02X", header->packet_type);
+ return PARSE_ERROR;
+ }
+
+ if (session->in.data_size + payload_size >
+ sizeof(session->in.buf)) {
+ error("Not enough incoming buffer space!");
+ return PARSE_ERROR;
+ }
+
+ memcpy(session->in.buf + session->in.data_size, payload, payload_size);
+ session->in.data_size += payload_size;
+
+ if (session->in.no_of_packets > 1) {
+ session->in.no_of_packets--;
+ DBG("Received AVDTP fragment. %d to go",
+ session->in.no_of_packets);
+ return PARSE_FRAGMENT;
+ }
+
+ session->in.active = FALSE;
+
+ return PARSE_SUCCESS;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avdtp *session = data;
+ struct avdtp_common_header *header;
+ ssize_t size;
+ int fd;
+
+ DBG("");
+
+ if (cond & G_IO_NVAL) {
+ session->io_id = 0;
+
+ return FALSE;
+ }
+
+ header = (void *) session->buf;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ goto failed;
+
+ fd = g_io_channel_unix_get_fd(chan);
+ size = read(fd, session->buf, session->imtu);
+ if (size < 0) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ if ((size_t) size < sizeof(struct avdtp_common_header)) {
+ error("Received too small packet (%zu bytes)", size);
+ goto failed;
+ }
+
+ switch (avdtp_parse_data(session, session->buf, size)) {
+ case PARSE_ERROR:
+ goto failed;
+ case PARSE_FRAGMENT:
+ return TRUE;
+ case PARSE_SUCCESS:
+ break;
+ }
+
+ /* Take a reference to protect against callback destroying session */
+ avdtp_ref(session);
+
+ if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) {
+ if (!avdtp_parse_cmd(session, session->in.transaction,
+ session->in.signal_id,
+ session->in.buf,
+ session->in.data_size)) {
+ error("Unable to handle command. Disconnecting");
+ goto failed;
+ }
+
+ if (session->req && session->req->collided) {
+ DBG("Collision detected");
+ goto next;
+ }
+
+ avdtp_unref(session);
+ return TRUE;
+ }
+
+ if (session->req == NULL) {
+ error("No pending request, ignoring message");
+ avdtp_unref(session);
+ return TRUE;
+ }
+
+ if (header->transaction != session->req->transaction) {
+ error("Transaction label doesn't match");
+ avdtp_unref(session);
+ return TRUE;
+ }
+
+ if (session->in.signal_id != session->req->signal_id) {
+ error("Response signal doesn't match");
+ avdtp_unref(session);
+ return TRUE;
+ }
+
+ g_source_remove(session->req->timeout);
+ session->req->timeout = 0;
+
+ switch (header->message_type) {
+ case AVDTP_MSG_TYPE_ACCEPT:
+ if (!avdtp_parse_resp(session, session->req->stream,
+ session->in.transaction,
+ session->in.signal_id,
+ session->in.buf,
+ session->in.data_size)) {
+ error("Unable to parse accept response");
+ goto failed;
+ }
+ break;
+ case AVDTP_MSG_TYPE_REJECT:
+ if (!avdtp_parse_rej(session, session->req->stream,
+ session->in.transaction,
+ session->in.signal_id,
+ session->in.buf,
+ session->in.data_size)) {
+ error("Unable to parse reject response");
+ goto failed;
+ }
+ break;
+ case AVDTP_MSG_TYPE_GEN_REJECT:
+ error("Received a General Reject message");
+ break;
+ default:
+ error("Unknown message type 0x%02X", header->message_type);
+ break;
+ }
+
+next:
+ pending_req_free(session->req);
+ session->req = NULL;
+
+ if (session->ref > 1)
+ process_queue(session);
+
+ avdtp_unref(session);
+
+ return TRUE;
+
+failed:
+ session->io_id = 0;
+ connection_lost(session, EIO);
+
+ return FALSE;
+}
+
+static int set_priority(int fd, int priority)
+{
+ int err;
+
+ err = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority,
+ sizeof(priority));
+ if (err == 0 || errno == ENOTSOCK)
+ return 0;
+
+ err = -errno;
+ error("setsockopt(SO_PRIORITY): %s (%d)", strerror(-err), -err);
+
+ return err;
+}
+
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+ struct queue *lseps)
+{
+ struct avdtp *session;
+ GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ int new_fd;
+
+ if (!lseps)
+ return NULL;
+
+ new_fd = dup(fd);
+ if (new_fd < 0) {
+ error("dup(): %s (%d)", strerror(errno), errno);
+ return NULL;
+ }
+
+ if (set_priority(new_fd, 6) < 0)
+ return NULL;
+
+ session = g_new0(struct avdtp, 1);
+ session->io = g_io_channel_unix_new(new_fd);
+ session->version = version;
+ session->imtu = imtu;
+ session->omtu = omtu;
+ session->buf = g_malloc0(MAX(session->imtu, session->omtu));
+
+ /* This watch should be low priority since otherwise the
+ * connect callback might be dispatched before the session
+ * callback if the kernel wakes us up at the same time for
+ * them. This could happen if a headset is very quick in
+ * sending the Start command after connecting the stream
+ * transport channel.
+ */
+ session->io_id = g_io_add_watch_full(session->io, G_PRIORITY_LOW, cond,
+ (GIOFunc) session_cb, session,
+ NULL);
+
+ session->lseps = lseps;
+
+ return avdtp_ref(session);
+}
+
+unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
+ avdtp_disconnect_cb_t cb,
+ void *user_data)
+{
+ struct disconnect_callback *callback;
+ static unsigned int id = 0;
+
+ callback = g_new0(struct disconnect_callback, 1);
+ callback->id = ++id;
+ callback->cb = cb;
+ callback->user_data = user_data;
+ session->disconnect = g_slist_append(session->disconnect, callback);
+
+ return id;
+}
+
+gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id)
+{
+ GSList *l;
+
+ for (l = session->disconnect; l; l = g_slist_next(l)) {
+ struct disconnect_callback *callback = l->data;
+
+ if (callback->id != id)
+ continue;
+
+ session->disconnect = g_slist_remove(session->disconnect,
+ callback);
+ g_free(callback);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void avdtp_shutdown(struct avdtp *session)
+{
+ GSList *l;
+ bool aborting = false;
+
+ if (!session->io)
+ return;
+
+ for (l = session->streams; l; l = g_slist_next(l)) {
+ struct avdtp_stream *stream = l->data;
+
+ if (stream->abort_int ||
+ avdtp_close(session, stream, TRUE) == 0)
+ aborting = true;
+ }
+
+ if (aborting) {
+ /* defer shutdown until all streams are aborted properly */
+ session->shutdown = true;
+ } else {
+ int sock = g_io_channel_unix_get_fd(session->io);
+
+ shutdown(sock, SHUT_RDWR);
+ }
+}
+
+static void queue_request(struct avdtp *session, struct pending_req *req,
+ gboolean priority)
+{
+ if (priority)
+ session->prio_queue = g_slist_append(session->prio_queue, req);
+ else
+ session->req_queue = g_slist_append(session->req_queue, req);
+}
+
+static uint8_t req_get_seid(struct pending_req *req)
+{
+ if (req->signal_id == AVDTP_DISCOVER)
+ return 0;
+
+ return ((struct seid_req *) (req->data))->acp_seid;
+}
+
+static int cancel_request(struct avdtp *session, int err)
+{
+ struct pending_req *req;
+ struct seid_req sreq;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_stream *stream;
+ uint8_t seid;
+ struct avdtp_error averr;
+
+ req = session->req;
+ session->req = NULL;
+
+ avdtp_error_init(&averr, AVDTP_ERRNO, err);
+
+ seid = req_get_seid(req);
+ if (seid)
+ stream = find_stream_by_rseid(session, seid);
+ else
+ stream = NULL;
+
+ if (stream) {
+ stream->abort_int = TRUE;
+ lsep = stream->lsep;
+ } else
+ lsep = NULL;
+
+ switch (req->signal_id) {
+ case AVDTP_RECONFIGURE:
+ error("Reconfigure: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+ lsep->cfm->reconfigure(session, lsep, stream, &averr,
+ lsep->user_data);
+ break;
+ case AVDTP_OPEN:
+ error("Open: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->open)
+ lsep->cfm->open(session, lsep, stream, &averr,
+ lsep->user_data);
+ break;
+ case AVDTP_START:
+ error("Start: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->start) {
+ lsep->cfm->start(session, lsep, stream, &averr,
+ lsep->user_data);
+ if (stream)
+ stream->starting = FALSE;
+ }
+ break;
+ case AVDTP_SUSPEND:
+ error("Suspend: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->suspend)
+ lsep->cfm->suspend(session, lsep, stream, &averr,
+ lsep->user_data);
+ break;
+ case AVDTP_CLOSE:
+ error("Close: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->close) {
+ lsep->cfm->close(session, lsep, stream, &averr,
+ lsep->user_data);
+ if (stream)
+ stream->close_int = FALSE;
+ }
+ break;
+ case AVDTP_SET_CONFIGURATION:
+ error("SetConfiguration: %s (%d)", strerror(err), err);
+ if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+ lsep->cfm->set_configuration(session, lsep, stream,
+ &averr, lsep->user_data);
+ goto failed;
+ case AVDTP_DISCOVER:
+ error("Discover: %s (%d)", strerror(err), err);
+ goto failed;
+ case AVDTP_GET_CAPABILITIES:
+ error("GetCapabilities: %s (%d)", strerror(err), err);
+ goto failed;
+ case AVDTP_ABORT:
+ error("Abort: %s (%d)", strerror(err), err);
+ goto failed;
+ }
+
+ if (!stream)
+ goto failed;
+
+ memset(&sreq, 0, sizeof(sreq));
+ sreq.acp_seid = seid;
+
+ err = send_request(session, TRUE, stream, AVDTP_ABORT, &sreq,
+ sizeof(sreq));
+ if (err < 0) {
+ error("Unable to send abort request");
+ goto failed;
+ }
+
+ goto done;
+
+failed:
+ connection_lost(session, err);
+done:
+ pending_req_free(req);
+ return err;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ struct avdtp *session = user_data;
+
+ cancel_request(session, ETIMEDOUT);
+
+ return FALSE;
+}
+
+static int send_req(struct avdtp *session, gboolean priority,
+ struct pending_req *req)
+{
+ static int transaction = 0;
+ int err;
+
+ if (session->req != NULL) {
+ queue_request(session, req, priority);
+ return 0;
+ }
+
+ req->transaction = transaction++;
+ transaction %= 16;
+
+ /* FIXME: Should we retry to send if the buffer
+ was not totally sent or in case of EINTR? */
+ if (!avdtp_send(session, req->transaction, AVDTP_MSG_TYPE_COMMAND,
+ req->signal_id, req->data, req->data_size)) {
+ err = -EIO;
+ goto failed;
+ }
+
+ session->req = req;
+
+ req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ?
+ ABORT_TIMEOUT : REQ_TIMEOUT,
+ request_timeout,
+ session);
+ return 0;
+
+failed:
+ g_free(req->data);
+ g_free(req);
+ return err;
+}
+
+static int send_request(struct avdtp *session, gboolean priority,
+ struct avdtp_stream *stream, uint8_t signal_id,
+ void *buffer, size_t size)
+{
+ struct pending_req *req;
+
+ if (size > 0 && !buffer) {
+ DBG("Invalid buffer %p", buffer);
+ return -EINVAL;
+ }
+
+ if (stream && stream->abort_int && signal_id != AVDTP_ABORT) {
+ DBG("Unable to send requests while aborting");
+ return -EINVAL;
+ }
+
+ req = g_new0(struct pending_req, 1);
+ req->signal_id = signal_id;
+ req->data_size = size;
+ req->stream = stream;
+
+ if (size > 0) {
+ req->data = g_malloc(size);
+ memcpy(req->data, buffer, size);
+ }
+
+ return send_req(session, priority, req);
+}
+
+static gboolean avdtp_discover_resp(struct avdtp *session,
+ struct discover_resp *resp, int size)
+{
+ int sep_count, i;
+ uint8_t getcap_cmd;
+ int ret = 0;
+ gboolean getcap_pending = FALSE;
+
+ if (session->version >= 0x0103)
+ getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
+ else
+ getcap_cmd = AVDTP_GET_CAPABILITIES;
+
+ sep_count = size / sizeof(struct seid_info);
+
+ for (i = 0; i < sep_count; i++) {
+ struct avdtp_remote_sep *sep;
+ struct avdtp_stream *stream;
+ struct seid_req req;
+
+ DBG("seid %d type %d media %d in use %d",
+ resp->seps[i].seid, resp->seps[i].type,
+ resp->seps[i].media_type, resp->seps[i].inuse);
+
+ stream = find_stream_by_rseid(session, resp->seps[i].seid);
+
+ sep = find_remote_sep(session->seps, resp->seps[i].seid);
+ if (!sep) {
+ if (resp->seps[i].inuse && !stream)
+ continue;
+ sep = g_new0(struct avdtp_remote_sep, 1);
+ session->seps = g_slist_append(session->seps, sep);
+ }
+
+ sep->stream = stream;
+ sep->seid = resp->seps[i].seid;
+ sep->type = resp->seps[i].type;
+ sep->media_type = resp->seps[i].media_type;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = sep->seid;
+
+ ret = send_request(session, TRUE, NULL, getcap_cmd,
+ &req, sizeof(req));
+ if (ret < 0)
+ break;
+ getcap_pending = TRUE;
+ }
+
+ if (!getcap_pending)
+ finalize_discovery(session, -ret);
+
+ return TRUE;
+}
+
+static gboolean avdtp_get_capabilities_resp(struct avdtp *session,
+ struct getcap_resp *resp,
+ unsigned int size)
+{
+ struct avdtp_remote_sep *sep;
+ uint8_t seid;
+
+ /* Check for minimum required packet size includes:
+ * 1. getcap resp header
+ * 2. media transport capability (2 bytes)
+ * 3. media codec capability type + length (2 bytes)
+ * 4. the actual media codec elements
+ * */
+ if (size < (sizeof(struct getcap_resp) + 4 +
+ sizeof(struct avdtp_media_codec_capability))) {
+ error("Too short getcap resp packet");
+ return FALSE;
+ }
+
+ seid = ((struct seid_req *) session->req->data)->acp_seid;
+
+ sep = find_remote_sep(session->seps, seid);
+
+ DBG("seid %d type %d media %d", sep->seid,
+ sep->type, sep->media_type);
+
+ if (sep->caps) {
+ g_slist_free_full(sep->caps, g_free);
+ sep->caps = NULL;
+ sep->codec = NULL;
+ sep->delay_reporting = FALSE;
+ }
+
+ sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
+ &sep->codec, &sep->delay_reporting);
+
+ return TRUE;
+}
+
+static gboolean avdtp_set_configuration_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_single_header *resp,
+ int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+
+ if (sep->cfm && sep->cfm->set_configuration)
+ sep->cfm->set_configuration(session, sep, stream, NULL,
+ sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_reconfigure_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_single_header *resp,
+ int size)
+{
+ return TRUE;
+}
+
+static gboolean avdtp_open_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ session->pending_open = stream;
+
+ if (!stream->open_acp && sep->cfm && sep->cfm->open)
+ sep->cfm->open(session, sep, stream, NULL, sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_start_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ /* We might be in STREAMING already if both sides send START_CMD at the
+ * same time and the one in SNK role doesn't reject it as it should */
+ if (sep->state != AVDTP_STATE_STREAMING)
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+
+ if (sep->cfm && sep->cfm->start)
+ sep->cfm->start(session, sep, stream, NULL, sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_close_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+ close_stream(stream);
+
+ return TRUE;
+}
+
+static gboolean avdtp_suspend_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ void *data, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+ if (sep->cfm && sep->cfm->suspend)
+ sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_abort_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
+
+ if (sep->cfm && sep->cfm->abort)
+ sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+
+ return TRUE;
+}
+
+static gboolean avdtp_delay_report_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ void *data, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->delay_report)
+ sep->cfm->delay_report(session, sep, stream, NULL,
+ sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_parse_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ uint8_t transaction, uint8_t signal_id,
+ void *buf, int size)
+{
+ struct pending_req *next;
+ const char *get_all = "";
+
+ if (session->prio_queue)
+ next = session->prio_queue->data;
+ else if (session->req_queue)
+ next = session->req_queue->data;
+ else
+ next = NULL;
+
+ switch (signal_id) {
+ case AVDTP_DISCOVER:
+ DBG("DISCOVER request succeeded");
+ return avdtp_discover_resp(session, buf, size);
+ case AVDTP_GET_ALL_CAPABILITIES:
+ get_all = "ALL_";
+ case AVDTP_GET_CAPABILITIES:
+ DBG("GET_%sCAPABILITIES request succeeded", get_all);
+ if (!avdtp_get_capabilities_resp(session, buf, size))
+ return FALSE;
+ if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES ||
+ next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
+ finalize_discovery(session, 0);
+ return TRUE;
+ }
+
+ /* The remaining commands require an existing stream so bail out
+ * here if the stream got unexpectedly disconnected */
+ if (!stream) {
+ DBG("AVDTP: stream was closed while waiting for reply");
+ return TRUE;
+ }
+
+ switch (signal_id) {
+ case AVDTP_SET_CONFIGURATION:
+ DBG("SET_CONFIGURATION request succeeded");
+ return avdtp_set_configuration_resp(session, stream,
+ buf, size);
+ case AVDTP_RECONFIGURE:
+ DBG("RECONFIGURE request succeeded");
+ return avdtp_reconfigure_resp(session, stream, buf, size);
+ case AVDTP_OPEN:
+ DBG("OPEN request succeeded");
+ return avdtp_open_resp(session, stream, buf, size);
+ case AVDTP_SUSPEND:
+ DBG("SUSPEND request succeeded");
+ return avdtp_suspend_resp(session, stream, buf, size);
+ case AVDTP_START:
+ DBG("START request succeeded");
+ return avdtp_start_resp(session, stream, buf, size);
+ case AVDTP_CLOSE:
+ DBG("CLOSE request succeeded");
+ return avdtp_close_resp(session, stream, buf, size);
+ case AVDTP_ABORT:
+ DBG("ABORT request succeeded");
+ return avdtp_abort_resp(session, stream, buf, size);
+ case AVDTP_DELAY_REPORT:
+ DBG("DELAY_REPORT request succeeded");
+ return avdtp_delay_report_resp(session, stream, buf, size);
+ }
+
+ error("Unknown signal id in accept response: %u", signal_id);
+ return TRUE;
+}
+
+static gboolean seid_rej_to_err(struct seid_rej *rej, unsigned int size,
+ struct avdtp_error *err)
+{
+ if (size < sizeof(struct seid_rej)) {
+ error("Too small packet for seid_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, 0x00, rej->error);
+
+ return TRUE;
+}
+
+static gboolean conf_rej_to_err(struct conf_rej *rej, unsigned int size,
+ struct avdtp_error *err)
+{
+ if (size < sizeof(struct conf_rej)) {
+ error("Too small packet for conf_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, rej->category, rej->error);
+
+ return TRUE;
+}
+
+static gboolean stream_rej_to_err(struct stream_rej *rej, unsigned int size,
+ struct avdtp_error *err,
+ uint8_t *acp_seid)
+{
+ if (size < sizeof(struct stream_rej)) {
+ error("Too small packet for stream_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, 0x00, rej->error);
+
+ if (acp_seid)
+ *acp_seid = rej->acp_seid;
+
+ return TRUE;
+}
+
+static gboolean avdtp_parse_rej(struct avdtp *session,
+ struct avdtp_stream *stream,
+ uint8_t transaction, uint8_t signal_id,
+ void *buf, int size)
+{
+ struct avdtp_error err;
+ uint8_t acp_seid;
+ struct avdtp_local_sep *sep = stream ? stream->lsep : NULL;
+
+ switch (signal_id) {
+ case AVDTP_DISCOVER:
+ case AVDTP_GET_CAPABILITIES:
+ case AVDTP_GET_ALL_CAPABILITIES:
+ if (!seid_rej_to_err(buf, size, &err))
+ return FALSE;
+ error("%s request rejected: %s (%d)",
+ signal_id == AVDTP_DISCOVER ? "DISCOVER" :
+ signal_id == AVDTP_GET_CAPABILITIES ?
+ "GET_CAPABILITIES" : "GET_ALL_CAPABILITIES",
+ avdtp_strerror(&err), err.err.error_code);
+ if (session->discover) {
+ session->discover->cb(session, session->seps, &err,
+ session->discover->user_data);
+ g_free(session->discover);
+ session->discover = NULL;
+ }
+ return TRUE;
+ case AVDTP_OPEN:
+ if (!seid_rej_to_err(buf, size, &err))
+ return FALSE;
+ error("OPEN request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->open)
+ sep->cfm->open(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_SET_CONFIGURATION:
+ if (!conf_rej_to_err(buf, size, &err))
+ return FALSE;
+ error("SET_CONFIGURATION request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->set_configuration)
+ sep->cfm->set_configuration(session, sep, stream,
+ &err, sep->user_data);
+ return TRUE;
+ case AVDTP_GET_CONFIGURATION:
+ if (!seid_rej_to_err(buf, size, &err))
+ return FALSE;
+ error("GET_CONFIGURATION request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->get_configuration)
+ sep->cfm->get_configuration(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_RECONFIGURE:
+ if (!conf_rej_to_err(buf, size, &err))
+ return FALSE;
+ error("RECONFIGURE request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->reconfigure)
+ sep->cfm->reconfigure(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_START:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("START request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->start) {
+ stream->starting = FALSE;
+ sep->cfm->start(session, sep, stream, &err,
+ sep->user_data);
+ }
+ return TRUE;
+ case AVDTP_SUSPEND:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("SUSPEND request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->suspend)
+ sep->cfm->suspend(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_CLOSE:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("CLOSE request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->close) {
+ sep->cfm->close(session, sep, stream, &err,
+ sep->user_data);
+ stream->close_int = FALSE;
+ }
+ return TRUE;
+ case AVDTP_ABORT:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("ABORT request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->abort)
+ sep->cfm->abort(session, sep, stream, &err,
+ sep->user_data);
+ return FALSE;
+ case AVDTP_DELAY_REPORT:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("DELAY_REPORT request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->delay_report)
+ sep->cfm->delay_report(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ default:
+ error("Unknown reject response signal id: %u", signal_id);
+ return TRUE;
+ }
+}
+
+struct avdtp_service_capability *avdtp_stream_get_codec(
+ struct avdtp_stream *stream)
+{
+ GSList *l;
+
+ for (l = stream->caps; l; l = l->next) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (cap->category == AVDTP_MEDIA_CODEC)
+ return cap;
+ }
+
+ return NULL;
+}
+
+static gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
+ struct avdtp_service_capability *cap)
+{
+ GSList *l;
+ struct avdtp_service_capability *stream_cap;
+
+ for (l = stream->caps; l; l = g_slist_next(l)) {
+ stream_cap = l->data;
+
+ if (stream_cap->category != cap->category ||
+ stream_cap->length != cap->length)
+ continue;
+
+ if (memcmp(stream_cap->data, cap->data, cap->length) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+ GSList *caps)
+{
+ for (; caps; caps = g_slist_next(caps)) {
+ struct avdtp_service_capability *cap = caps->data;
+
+ if (!avdtp_stream_has_capability(stream, cap))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+ struct avdtp_stream *stream)
+{
+ GSList *l;
+
+ for (l = stream->session->seps; l; l = l->next) {
+ struct avdtp_remote_sep *sep = l->data;
+
+ if (sep->seid == stream->rseid)
+ return sep;
+ }
+
+ return NULL;
+}
+
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+ size_t imtu, size_t omtu)
+{
+ GIOChannel *io;
+
+ if (stream != stream->session->pending_open)
+ return FALSE;
+
+ if (set_priority(fd, 5) < 0)
+ return FALSE;
+
+ io = g_io_channel_unix_new(fd);
+
+ handle_transport_connect(stream->session, io, imtu, omtu);
+
+ g_io_channel_unref(io);
+
+ return TRUE;
+}
+
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+ uint16_t *imtu, uint16_t *omtu,
+ GSList **caps)
+{
+ if (stream->io == NULL)
+ return FALSE;
+
+ if (sock)
+ *sock = g_io_channel_unix_get_fd(stream->io);
+
+ if (omtu)
+ *omtu = stream->omtu;
+
+ if (imtu)
+ *imtu = stream->imtu;
+
+ if (caps)
+ *caps = stream->caps;
+
+ return TRUE;
+}
+
+static int process_queue(struct avdtp *session)
+{
+ GSList **queue, *l;
+ struct pending_req *req;
+
+ if (session->req)
+ return 0;
+
+ if (session->prio_queue)
+ queue = &session->prio_queue;
+ else
+ queue = &session->req_queue;
+
+ if (!*queue)
+ return 0;
+
+ l = *queue;
+ req = l->data;
+
+ *queue = g_slist_remove(*queue, req);
+
+ return send_req(session, FALSE, req);
+}
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep)
+{
+ return sep->codec;
+}
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+ const void *data,
+ int length)
+{
+ struct avdtp_service_capability *cap;
+
+ if (category < AVDTP_MEDIA_TRANSPORT ||
+ category > AVDTP_DELAY_REPORTING)
+ return NULL;
+
+ if (length > 0 && !data)
+ return NULL;
+
+ cap = g_malloc(sizeof(struct avdtp_service_capability) + length);
+ cap->category = category;
+ cap->length = length;
+
+ if (length > 0)
+ memcpy(cap->data, data, length);
+
+ return cap;
+}
+
+static gboolean process_discover(gpointer data)
+{
+ struct avdtp *session = data;
+
+ session->discover->id = 0;
+
+ finalize_discovery(session, 0);
+
+ return FALSE;
+}
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+ void *user_data)
+{
+ int err;
+
+ if (session->discover)
+ return -EBUSY;
+
+ session->discover = g_new0(struct discover_callback, 1);
+
+ if (session->seps) {
+ session->discover->cb = cb;
+ session->discover->user_data = user_data;
+ session->discover->id = g_idle_add(process_discover, session);
+ return 0;
+ }
+
+ err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
+ if (err == 0) {
+ session->discover->cb = cb;
+ session->discover->user_data = user_data;
+ }
+
+ return err;
+}
+
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ unsigned int id)
+{
+ GSList *l;
+ struct stream_callback *cb;
+
+ if (!stream)
+ return FALSE;
+
+ for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) {
+ struct stream_callback *tmp = l->data;
+ if (tmp && tmp->id == id) {
+ cb = tmp;
+ break;
+ }
+ }
+
+ if (!cb)
+ return FALSE;
+
+ stream->callbacks = g_slist_remove(stream->callbacks, cb);
+ g_free(cb);
+
+ return TRUE;
+}
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ avdtp_stream_state_cb cb, void *data)
+{
+ struct stream_callback *stream_cb;
+ static unsigned int id = 0;
+
+ stream_cb = g_new(struct stream_callback, 1);
+ stream_cb->cb = cb;
+ stream_cb->user_data = data;
+ stream_cb->id = ++id;
+
+ stream->callbacks = g_slist_append(stream->callbacks, stream_cb);
+
+ return stream_cb->id;
+}
+
+int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, AVDTP_GET_CONFIGURATION,
+ &req, sizeof(req));
+}
+
+static void copy_capabilities(gpointer data, gpointer user_data)
+{
+ struct avdtp_service_capability *src_cap = data;
+ struct avdtp_service_capability *dst_cap;
+ GSList **l = user_data;
+
+ dst_cap = avdtp_service_cap_new(src_cap->category, src_cap->data,
+ src_cap->length);
+
+ *l = g_slist_append(*l, dst_cap);
+}
+
+int avdtp_set_configuration(struct avdtp *session,
+ struct avdtp_remote_sep *rsep,
+ struct avdtp_local_sep *lsep,
+ GSList *caps,
+ struct avdtp_stream **stream)
+{
+ struct setconf_req *req;
+ struct avdtp_stream *new_stream;
+ unsigned char *ptr;
+ int err, caps_len;
+ struct avdtp_service_capability *cap;
+ GSList *l;
+
+ if (!(lsep && rsep))
+ return -EINVAL;
+
+ DBG("%p: int_seid=%u, acp_seid=%u", session,
+ lsep->info.seid, rsep->seid);
+
+ new_stream = g_new0(struct avdtp_stream, 1);
+ new_stream->session = session;
+ new_stream->lsep = lsep;
+ new_stream->rseid = rsep->seid;
+
+ if (rsep->delay_reporting && lsep->delay_reporting) {
+ struct avdtp_service_capability *delay_reporting;
+
+ delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+ NULL, 0);
+ caps = g_slist_append(caps, delay_reporting);
+ new_stream->delay_reporting = TRUE;
+ }
+
+ g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
+
+ /* Calculate total size of request */
+ for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ caps_len += cap->length + 2;
+ }
+
+ req = g_malloc0(sizeof(struct setconf_req) + caps_len);
+
+ req->int_seid = lsep->info.seid;
+ req->acp_seid = rsep->seid;
+
+ /* Copy the capabilities into the request */
+ for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ memcpy(ptr, cap, cap->length + 2);
+ ptr += cap->length + 2;
+ }
+
+ err = send_request(session, FALSE, new_stream,
+ AVDTP_SET_CONFIGURATION, req,
+ sizeof(struct setconf_req) + caps_len);
+ if (err < 0)
+ stream_free(new_stream);
+ else {
+ lsep->info.inuse = 1;
+ lsep->stream = new_stream;
+ rsep->stream = new_stream;
+ session->streams = g_slist_append(session->streams, new_stream);
+ if (stream)
+ *stream = new_stream;
+ }
+
+ g_free(req);
+
+ return err;
+}
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state > AVDTP_STATE_CONFIGURED)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, AVDTP_OPEN,
+ &req, sizeof(req));
+}
+
+static gboolean start_timeout(gpointer user_data)
+{
+ struct avdtp_stream *stream = user_data;
+ struct avdtp *session = stream->session;
+
+ stream->open_acp = FALSE;
+
+ if (avdtp_start(session, stream) < 0)
+ error("wait_timeout: avdtp_start failed");
+
+ stream->start_timer = 0;
+
+ return FALSE;
+}
+
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct start_req req;
+ int ret;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state != AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ /* Recommendation 12:
+ * If the RD has configured and opened a stream it is also responsible
+ * to start the streaming via GAVDP_START.
+ */
+ if (stream->open_acp) {
+ /* If timer already active wait it */
+ if (stream->start_timer)
+ return 0;
+
+ stream->start_timer = g_timeout_add_seconds(START_TIMEOUT,
+ start_timeout,
+ stream);
+ return 0;
+ }
+
+ if (stream->close_int == TRUE) {
+ error("avdtp_start: rejecting start since close is initiated");
+ return -EINVAL;
+ }
+
+ if (stream->starting == TRUE) {
+ DBG("stream already started");
+ return -EINPROGRESS;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.first_seid.seid = stream->rseid;
+
+ ret = send_request(session, FALSE, stream, AVDTP_START,
+ &req, sizeof(req));
+ if (ret == 0)
+ stream->starting = TRUE;
+
+ return ret;
+}
+
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+ gboolean immediate)
+{
+ struct seid_req req;
+ int ret;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->close_int == TRUE) {
+ error("avdtp_close: rejecting since close is already initiated");
+ return -EINVAL;
+ }
+
+ /* If stream is not yet in the OPEN state, let's use ABORT_CMD */
+ if (stream->lsep->state < AVDTP_STATE_OPEN)
+ return avdtp_abort(session, stream);
+
+ if (immediate && session->req && stream == session->req->stream)
+ return avdtp_abort(session, stream);
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+
+ ret = send_request(session, FALSE, stream, AVDTP_CLOSE,
+ &req, sizeof(req));
+ if (ret == 0)
+ stream->close_int = TRUE;
+
+ return ret;
+}
+
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state <= AVDTP_STATE_OPEN || stream->close_int)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, AVDTP_SUSPEND,
+ &req, sizeof(req));
+}
+
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+ int ret;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state == AVDTP_STATE_ABORTING)
+ return -EINVAL;
+
+ if (session->req && session->req->timeout > 0 &&
+ stream == session->req->stream)
+ return cancel_request(session, ECANCELED);
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+
+ ret = send_request(session, TRUE, stream, AVDTP_ABORT,
+ &req, sizeof(req));
+ if (ret == 0)
+ stream->abort_int = TRUE;
+
+ return ret;
+}
+
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+ uint16_t delay)
+{
+ struct delay_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state != AVDTP_STATE_CONFIGURED &&
+ stream->lsep->state != AVDTP_STATE_STREAMING)
+ return -EINVAL;
+
+ if (!stream->delay_reporting || session->version < 0x0103)
+ return -EINVAL;
+
+ stream->delay = delay;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+ req.delay = htons(delay);
+
+ return send_request(session, TRUE, stream, AVDTP_DELAY_REPORT,
+ &req, sizeof(req));
+}
+
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+ uint8_t media_type,
+ uint8_t codec_type,
+ gboolean delay_reporting,
+ struct avdtp_sep_ind *ind,
+ struct avdtp_sep_cfm *cfm,
+ void *user_data)
+{
+ struct avdtp_local_sep *sep;
+ uint8_t seid = util_get_uid(&seids, MAX_SEID);
+
+ if (!seid)
+ return NULL;
+
+ sep = g_new0(struct avdtp_local_sep, 1);
+
+ sep->state = AVDTP_STATE_IDLE;
+ sep->info.seid = seid;
+ sep->info.type = type;
+ sep->info.media_type = media_type;
+ sep->codec = codec_type;
+ sep->ind = ind;
+ sep->cfm = cfm;
+ sep->user_data = user_data;
+ sep->delay_reporting = delay_reporting;
+
+ DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
+ sep->info.type, sep->codec, sep->info.seid);
+
+ queue_push_tail(lseps, sep);
+
+ return sep;
+}
+
+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+ uint16_t codec_id)
+{
+ sep->vndcodec_vendor = vendor_id;
+ sep->vndcodec_codec = codec_id;
+}
+
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep)
+{
+ if (!sep)
+ return -EINVAL;
+
+ if (sep->stream)
+ release_stream(sep->stream, sep->stream->session);
+
+ DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep,
+ sep->info.type, sep->codec, sep->info.seid);
+
+ util_clear_uid(&seids, sep->info.seid);
+ queue_remove(lseps, sep);
+ g_free(sep);
+
+ return 0;
+}
+
+const char *avdtp_strerror(struct avdtp_error *err)
+{
+ if (err->category == AVDTP_ERRNO)
+ return strerror(err->err.posix_errno);
+
+ switch (err->err.error_code) {
+ case AVDTP_BAD_HEADER_FORMAT:
+ return "Bad Header Format";
+ case AVDTP_BAD_LENGTH:
+ return "Bad Packet Length";
+ case AVDTP_BAD_ACP_SEID:
+ return "Bad Acceptor SEID";
+ case AVDTP_SEP_IN_USE:
+ return "Stream End Point in Use";
+ case AVDTP_SEP_NOT_IN_USE:
+ return "Stream End Point Not in Use";
+ case AVDTP_BAD_SERV_CATEGORY:
+ return "Bad Service Category";
+ case AVDTP_BAD_PAYLOAD_FORMAT:
+ return "Bad Payload format";
+ case AVDTP_NOT_SUPPORTED_COMMAND:
+ return "Command Not Supported";
+ case AVDTP_INVALID_CAPABILITIES:
+ return "Invalid Capabilities";
+ case AVDTP_BAD_RECOVERY_TYPE:
+ return "Bad Recovery Type";
+ case AVDTP_BAD_MEDIA_TRANSPORT_FORMAT:
+ return "Bad Media Transport Format";
+ case AVDTP_BAD_RECOVERY_FORMAT:
+ return "Bad Recovery Format";
+ case AVDTP_BAD_ROHC_FORMAT:
+ return "Bad Header Compression Format";
+ case AVDTP_BAD_CP_FORMAT:
+ return "Bad Content Protection Format";
+ case AVDTP_BAD_MULTIPLEXING_FORMAT:
+ return "Bad Multiplexing Format";
+ case AVDTP_UNSUPPORTED_CONFIGURATION:
+ return "Configuration not supported";
+ case AVDTP_BAD_STATE:
+ return "Bad State";
+ default:
+ return "Unknown error";
+ }
+}
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
+{
+ return sep->state;
+}
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
+{
+ return g_slist_find(session->streams, stream) ? TRUE : FALSE;
+}
diff --git a/repo/android/avdtp.h b/repo/android/avdtp.h
new file mode 100644
index 0000000..07516a8
--- /dev/null
+++ b/repo/android/avdtp.h
@@ -0,0 +1,291 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct avdtp;
+struct avdtp_stream;
+struct avdtp_local_sep;
+struct avdtp_remote_sep;
+struct avdtp_error {
+ uint8_t category;
+ union {
+ uint8_t error_code;
+ int posix_errno;
+ } err;
+};
+
+#define AVDTP_PSM 25
+
+/* SEP capability categories */
+#define AVDTP_MEDIA_TRANSPORT 0x01
+#define AVDTP_REPORTING 0x02
+#define AVDTP_RECOVERY 0x03
+#define AVDTP_CONTENT_PROTECTION 0x04
+#define AVDTP_HEADER_COMPRESSION 0x05
+#define AVDTP_MULTIPLEXING 0x06
+#define AVDTP_MEDIA_CODEC 0x07
+#define AVDTP_DELAY_REPORTING 0x08
+#define AVDTP_ERRNO 0xff
+
+/* AVDTP error definitions */
+#define AVDTP_BAD_HEADER_FORMAT 0x01
+#define AVDTP_BAD_LENGTH 0x11
+#define AVDTP_BAD_ACP_SEID 0x12
+#define AVDTP_SEP_IN_USE 0x13
+#define AVDTP_SEP_NOT_IN_USE 0x14
+#define AVDTP_BAD_SERV_CATEGORY 0x17
+#define AVDTP_BAD_PAYLOAD_FORMAT 0x18
+#define AVDTP_NOT_SUPPORTED_COMMAND 0x19
+#define AVDTP_INVALID_CAPABILITIES 0x1A
+#define AVDTP_BAD_RECOVERY_TYPE 0x22
+#define AVDTP_BAD_MEDIA_TRANSPORT_FORMAT 0x23
+#define AVDTP_BAD_RECOVERY_FORMAT 0x25
+#define AVDTP_BAD_ROHC_FORMAT 0x26
+#define AVDTP_BAD_CP_FORMAT 0x27
+#define AVDTP_BAD_MULTIPLEXING_FORMAT 0x28
+#define AVDTP_UNSUPPORTED_CONFIGURATION 0x29
+#define AVDTP_BAD_STATE 0x31
+
+/* SEP types definitions */
+#define AVDTP_SEP_TYPE_SOURCE 0x00
+#define AVDTP_SEP_TYPE_SINK 0x01
+
+/* Media types definitions */
+#define AVDTP_MEDIA_TYPE_AUDIO 0x00
+#define AVDTP_MEDIA_TYPE_VIDEO 0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02
+
+typedef enum {
+ AVDTP_STATE_IDLE,
+ AVDTP_STATE_CONFIGURED,
+ AVDTP_STATE_OPEN,
+ AVDTP_STATE_STREAMING,
+ AVDTP_STATE_CLOSING,
+ AVDTP_STATE_ABORTING,
+} avdtp_state_t;
+
+struct avdtp_service_capability {
+ uint8_t category;
+ uint8_t length;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_media_codec_capability {
+ uint8_t rfa0:4;
+ uint8_t media_type:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_media_codec_capability {
+ uint8_t media_type:4;
+ uint8_t rfa0:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+typedef void (*avdtp_stream_state_cb) (struct avdtp_stream *stream,
+ avdtp_state_t old_state,
+ avdtp_state_t new_state,
+ struct avdtp_error *err,
+ void *user_data);
+
+typedef void (*avdtp_set_configuration_cb) (struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err);
+
+/* Callbacks for when a reply is received to a command that we sent */
+struct avdtp_sep_cfm {
+ void (*set_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data);
+ void (*get_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data);
+ void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
+ void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
+ void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*reconfigure) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*delay_report) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+};
+
+/*
+ * Callbacks for indicating when we received a new command. The return value
+ * indicates whether the command should be rejected or accepted
+ */
+struct avdtp_sep_ind {
+ gboolean (*get_capability) (struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err,
+ void *user_data);
+ gboolean (*set_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ GSList *caps,
+ avdtp_set_configuration_cb cb,
+ void *user_data);
+ gboolean (*get_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data);
+ gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*suspend) (struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ void (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*reconfigure) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data);
+ gboolean (*delayreport) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t rseid, uint16_t delay,
+ uint8_t *err, void *user_data);
+};
+
+typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data);
+typedef void (*avdtp_disconnect_cb_t) (void *user_data);
+
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+ struct queue *lseps);
+
+unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
+ avdtp_disconnect_cb_t cb,
+ void *user_data);
+gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id);
+
+void avdtp_shutdown(struct avdtp *session);
+
+void avdtp_unref(struct avdtp *session);
+struct avdtp *avdtp_ref(struct avdtp *session);
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+ const void *data,
+ int size);
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+ void *user_data);
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream);
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ avdtp_stream_state_cb cb, void *data);
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ unsigned int id);
+
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+ size_t imtu, size_t omtu);
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+ uint16_t *imtu, uint16_t *omtu,
+ GSList **caps);
+struct avdtp_service_capability *avdtp_stream_get_codec(
+ struct avdtp_stream *stream);
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+ GSList *caps);
+struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
+ struct avdtp_stream *stream);
+
+int avdtp_set_configuration(struct avdtp *session,
+ struct avdtp_remote_sep *rsep,
+ struct avdtp_local_sep *lsep,
+ GSList *caps,
+ struct avdtp_stream **stream);
+
+int avdtp_get_configuration(struct avdtp *session,
+ struct avdtp_stream *stream);
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+ gboolean immediate);
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+ uint16_t delay);
+
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+ uint8_t media_type,
+ uint8_t codec_type,
+ gboolean delay_reporting,
+ struct avdtp_sep_ind *ind,
+ struct avdtp_sep_cfm *cfm,
+ void *user_data);
+void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
+ uint16_t codec_id);
+
+/* Find a matching pair of local and remote SEP ID's */
+struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
+ struct avdtp_local_sep *lsep);
+
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id);
+const char *avdtp_strerror(struct avdtp_error *err);
+uint8_t avdtp_error_category(struct avdtp_error *err);
+int avdtp_error_error_code(struct avdtp_error *err);
+int avdtp_error_posix_errno(struct avdtp_error *err);
diff --git a/repo/android/avdtptest.c b/repo/android/avdtptest.c
new file mode 100644
index 0000000..ce34443
--- /dev/null
+++ b/repo/android/avdtptest.c
@@ -0,0 +1,909 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
+#include "btio/btio.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "avdtp.h"
+
+static GMainLoop *mainloop = NULL;
+static int dev_role = AVDTP_SEP_TYPE_SOURCE;
+static bool preconf = false;
+static struct avdtp *avdtp = NULL;
+struct avdtp_stream *avdtp_stream = NULL;
+struct avdtp_local_sep *local_sep = NULL;
+struct avdtp_remote_sep *remote_sep = NULL;
+static GIOChannel *io = NULL;
+static bool reject = false;
+static bdaddr_t src;
+static bdaddr_t dst;
+static uint16_t version = 0x0103;
+static guint media_player = 0;
+static guint media_recorder = 0;
+static guint idle_id = 0;
+static struct queue *lseps = NULL;
+
+static bool fragment = false;
+
+static enum {
+ CMD_GET_CONF,
+ CMD_OPEN,
+ CMD_START,
+ CMD_SUSPEND,
+ CMD_CLOSE,
+ CMD_ABORT,
+ CMD_DELAY,
+ CMD_NONE,
+} command = CMD_NONE;
+
+static const char sbc_codec[] = {0x00, 0x00, 0x11, 0x15, 0x02, 0x40};
+static const char sbc_media_frame[] = {
+ 0x00, 0x60, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x9c, 0xfd, 0x40, 0xbd, 0xde, 0xa9, 0x75, 0x43, 0x20, 0x87, 0x64,
+ 0x44, 0x32, 0x7f, 0xbe, 0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x7f, 0xbe,
+ 0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x7f, 0xbe, 0xf7, 0x76, 0xfe, 0xf7,
+ 0xbb, 0xbb, 0x80, 0x3e, 0xf7, 0x76, 0xfe, 0xf7, 0xbb, 0xbb, 0x83, 0x41,
+ 0x07, 0x77, 0x09, 0x07, 0x43, 0xb3, 0x81, 0xbc, 0xf8, 0x77, 0x02, 0xe5,
+ 0xa4, 0x3a, 0xa0, 0xcb, 0x38, 0xbb, 0x57, 0x90, 0xd9, 0x08, 0x9c, 0x1d,
+ 0x86, 0x59, 0x01, 0x0c, 0x21, 0x44, 0x68, 0x35, 0xa8, 0x57, 0x97, 0x0e,
+ 0x9b, 0xbb, 0x62, 0xc4, 0xca, 0x57, 0x04, 0xa1, 0xca, 0x3b, 0xa3, 0x48,
+ 0xd2, 0x66, 0x11, 0x33, 0x6a, 0x3b, 0xb4, 0xbb, 0x08, 0x77, 0x17, 0x03,
+ 0xb4, 0x3b, 0x79, 0x3b, 0x46, 0x97, 0x0e, 0xf7, 0x3d, 0xbb, 0x3d, 0x49,
+ 0x25, 0x86, 0x88, 0xb4, 0xad, 0x3b, 0x62, 0xbb, 0xa4, 0x47, 0x29, 0x99,
+ 0x3b, 0x3b, 0xaf, 0xc6, 0xd4, 0x37, 0x68, 0x94, 0x0a, 0xbb
+ };
+
+static void parse_command(const char *cmd)
+{
+ if (!strncmp(cmd, "getconf", sizeof("getconf"))) {
+ command = CMD_GET_CONF;
+ } else if (!strncmp(cmd, "open", sizeof("open"))) {
+ command = CMD_OPEN;
+ } else if (!strncmp(cmd, "start", sizeof("start"))) {
+ command = CMD_START;
+ } else if (!strncmp(cmd, "suspend", sizeof("suspend"))) {
+ command = CMD_SUSPEND;
+ } else if (!strncmp(cmd, "close", sizeof("close"))) {
+ command = CMD_CLOSE;
+ } else if (!strncmp(cmd, "abort", sizeof("abort"))) {
+ command = CMD_ABORT;
+ } else if (!strncmp(cmd, "delay", sizeof("delay"))) {
+ command = CMD_DELAY;
+ } else {
+ printf("Unknown command '%s'\n", cmd);
+ printf("(getconf open start suspend close abort delay)\n");
+ exit(1);
+ }
+}
+
+static void send_command(void)
+{
+ avdtp_state_t state = avdtp_sep_get_state(local_sep);
+
+ switch (command) {
+ case CMD_GET_CONF:
+ avdtp_get_configuration(avdtp, avdtp_stream);
+ break;
+ case CMD_OPEN:
+ if (state == AVDTP_STATE_CONFIGURED)
+ avdtp_open(avdtp, avdtp_stream);
+ break;
+ case CMD_START:
+ if (state == AVDTP_STATE_OPEN)
+ avdtp_start(avdtp, avdtp_stream);
+ break;
+ case CMD_SUSPEND:
+ if (state == AVDTP_STATE_STREAMING)
+ avdtp_suspend(avdtp , avdtp_stream);
+ break;
+ case CMD_CLOSE:
+ if (state == AVDTP_STATE_STREAMING)
+ avdtp_close(avdtp, avdtp_stream, FALSE);
+ break;
+ case CMD_ABORT:
+ avdtp_abort(avdtp , avdtp_stream);
+ break;
+ case CMD_DELAY:
+ avdtp_delay_report(avdtp , avdtp_stream , 250);
+ break;
+ case CMD_NONE:
+ default:
+ break;
+ }
+}
+
+static gboolean media_writer(gpointer user_data)
+{
+ uint16_t omtu;
+ int fd;
+ int to_write;
+
+ if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+ return TRUE;
+
+ if (omtu < sizeof(sbc_media_frame))
+ to_write = omtu;
+ else
+ to_write = sizeof(sbc_media_frame);
+
+ if (write(fd, sbc_media_frame, to_write) < 0)
+ return TRUE;
+
+ send_command();
+
+ return TRUE;
+}
+
+static bool start_media_player(void)
+{
+ int fd;
+ uint16_t omtu;
+
+ printf("Media streaming started\n");
+
+ if (media_player || !avdtp_stream)
+ return false;
+
+ if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+ return false;
+
+ media_player = g_timeout_add(200, media_writer, NULL);
+ if (!media_player)
+ return false;
+
+ return true;
+}
+
+static void stop_media_player(void)
+{
+ if (!media_player)
+ return;
+
+ printf("Media streaming stopped\n");
+
+ g_source_remove(media_player);
+ media_player = 0;
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+ unsigned cc:4;
+ unsigned x:1;
+ unsigned p:1;
+ unsigned v:2;
+
+ unsigned pt:7;
+ unsigned m:1;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_header {
+ unsigned v:2;
+ unsigned p:1;
+ unsigned x:1;
+ unsigned cc:4;
+
+ unsigned m:1;
+ unsigned pt:7;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+static gboolean media_reader(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ char buf[UINT16_MAX];
+ struct rtp_header *rtp = (void *) buf;
+ static bool decode = false;
+ uint16_t imtu;
+ int fd, ret;
+
+ if (!avdtp_stream_get_transport(avdtp_stream, &fd, &imtu, NULL, NULL))
+ return TRUE;
+
+ ret = read(fd, buf, imtu);
+ if (ret < 0) {
+ printf("Reading failed (%s)\n", strerror(errno));
+ return TRUE;
+ }
+
+ if (ret < (int) sizeof(*rtp)) {
+ printf("Not enough media data received (%u bytes)", ret);
+ return TRUE;
+ }
+
+ if (!decode) {
+ printf("V=%u P=%u X=%u CC=%u M=%u PT=%u SeqNr=%d\n",
+ rtp->v, rtp->p, rtp->x, rtp->cc, rtp->m, rtp->pt,
+ be16_to_cpu(rtp->sequence_number));
+ decode = true;
+ }
+
+ send_command();
+
+ return TRUE;
+}
+
+static bool start_media_recorder(void)
+{
+ int fd;
+ uint16_t omtu;
+ GIOChannel *chan;
+
+ printf("Media recording started\n");
+
+ if (media_recorder || !avdtp_stream)
+ return false;
+
+ if (!avdtp_stream_get_transport(avdtp_stream, &fd, NULL, &omtu, NULL))
+ return false;
+
+ chan = g_io_channel_unix_new(fd);
+
+ media_recorder = g_io_add_watch(chan, G_IO_IN, media_reader, NULL);
+ g_io_channel_unref(chan);
+
+ if (!media_recorder)
+ return false;
+
+ return true;
+}
+
+static void stop_media_recorder(void)
+{
+ if (!media_recorder)
+ return;
+
+ printf("Media recording stopped\n");
+
+ g_source_remove(media_recorder);
+ media_recorder = 0;
+}
+
+static void set_configuration_cfm(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (preconf)
+ avdtp_open(avdtp, avdtp_stream);
+}
+
+static void get_configuration_cfm(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data)
+ {
+ printf("%s\n", __func__);
+}
+
+static void disconnect_cb(void *user_data)
+{
+ printf("Disconnected\n");
+
+ g_main_loop_quit(mainloop);
+}
+
+static void discover_cb(struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data)
+{
+ struct avdtp_service_capability *service;
+ GSList *caps = NULL;
+ int ret;
+
+ remote_sep = avdtp_find_remote_sep(avdtp, local_sep);
+ if (!remote_sep) {
+ printf("Unable to find matching endpoint\n");
+ avdtp_shutdown(session);
+ return;
+ }
+
+ printf("Matching endpoint found\n");
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+ caps = g_slist_append(caps, service);
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, sbc_codec,
+ sizeof(sbc_codec));
+ caps = g_slist_append(caps, service);
+
+ ret = avdtp_set_configuration(avdtp, remote_sep, local_sep, caps,
+ &avdtp_stream);
+
+ g_slist_free_full(caps, g_free);
+
+ if (ret < 0) {
+ printf("Failed to set configuration (%s)\n", strerror(-ret));
+ avdtp_shutdown(session);
+ }
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ uint16_t imtu, omtu;
+ GError *gerr = NULL;
+ int fd;
+
+ if (err) {
+ printf("%s\n", err->message);
+ g_main_loop_quit(mainloop);
+ return;
+ }
+
+ bt_io_get(chan, &gerr,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ printf("%s\n", gerr->message);
+ g_main_loop_quit(mainloop);
+ return;
+ }
+
+ printf("Connected (imtu=%d omtu=%d)\n", imtu, omtu);
+
+ fd = g_io_channel_unix_get_fd(chan);
+
+ if (avdtp && avdtp_stream) {
+ if (!avdtp_stream_set_transport(avdtp_stream, fd, imtu, omtu)) {
+ printf("avdtp_stream_set_transport: failed\n");
+ g_main_loop_quit(mainloop);
+ }
+
+ g_io_channel_set_close_on_unref(chan, FALSE);
+
+ send_command();
+
+ return;
+ }
+
+ avdtp = avdtp_new(fd, imtu, omtu, version, lseps);
+ if (!avdtp) {
+ printf("Failed to create avdtp instance\n");
+ g_main_loop_quit(mainloop);
+ return;
+ }
+
+ avdtp_add_disconnect_cb(avdtp, disconnect_cb, NULL);
+
+ if (preconf) {
+ int ret;
+
+ ret = avdtp_discover(avdtp, discover_cb, NULL);
+ if (ret < 0) {
+ printf("avdtp_discover failed: %s", strerror(-ret));
+ g_main_loop_quit(mainloop);
+ }
+ }
+}
+
+static GIOChannel *do_connect(GError **err)
+{
+ if (fragment)
+ return bt_io_connect(connect_cb, NULL, NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_MTU, 48,
+ BT_IO_OPT_INVALID);
+
+ return bt_io_connect(connect_cb, NULL, NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_INVALID);
+}
+
+static void open_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ GError *gerr = NULL;
+
+ printf("%s\n", __func__);
+
+ do_connect(&gerr);
+ if (gerr) {
+ printf("connect failed: %s\n", gerr->message);
+ g_error_free(gerr);
+ g_main_loop_quit(mainloop);
+ }
+}
+
+static void start_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ start_media_player();
+ else
+ start_media_recorder();
+}
+
+static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+}
+
+static void close_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+
+ avdtp_stream = NULL;
+}
+
+static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+
+ avdtp_stream = NULL;
+}
+
+static void reconfigure_cfm(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ printf("%s\n", __func__);
+}
+
+static void delay_report_cfm(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ printf("%s\n", __func__);
+}
+
+static struct avdtp_sep_cfm sep_cfm = {
+ .set_configuration = set_configuration_cfm,
+ .get_configuration = get_configuration_cfm,
+ .open = open_cfm,
+ .start = start_cfm,
+ .suspend = suspend_cfm,
+ .close = close_cfm,
+ .abort = abort_cfm,
+ .reconfigure = reconfigure_cfm,
+ .delay_report = delay_report_cfm,
+};
+
+static gboolean get_capability_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err,
+ void *user_data)
+{
+ struct avdtp_service_capability *service;
+ int i;
+
+ printf("%s\n", __func__);
+
+ if (idle_id > 0) {
+ g_source_remove(idle_id);
+ idle_id = 0;
+ }
+
+ if (reject)
+ return FALSE;
+
+ *caps = NULL;
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0);
+ *caps = g_slist_append(*caps, service);
+
+ service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, sbc_codec,
+ sizeof(sbc_codec));
+ *caps = g_slist_append(*caps, service);
+
+ if (fragment)
+ for (i = 0; i < 10; i++) {
+ service = avdtp_service_cap_new(AVDTP_MEDIA_CODEC,
+ sbc_codec,
+ sizeof(sbc_codec));
+ *caps = g_slist_append(*caps, service);
+ }
+
+ return TRUE;
+}
+
+static gboolean set_configuration_ind(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ GSList *caps,
+ avdtp_set_configuration_cb cb,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ if (idle_id > 0) {
+ g_source_remove(idle_id);
+ idle_id = 0;
+ }
+
+ avdtp_stream = stream;
+
+ cb(session, stream, NULL);
+
+ send_command();
+
+ return TRUE;
+}
+
+static gboolean get_configuration_ind(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ send_command();
+
+ return TRUE;
+}
+
+static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ start_media_player();
+ else
+ start_media_recorder();
+
+ send_command();
+
+ return TRUE;
+}
+
+static gboolean suspend_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+
+ return TRUE;
+}
+
+static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+
+ avdtp_stream = NULL;
+
+ return TRUE;
+}
+
+static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (dev_role == AVDTP_SEP_TYPE_SOURCE)
+ stop_media_player();
+ else
+ stop_media_recorder();
+
+ avdtp_stream = NULL;
+}
+
+static gboolean reconfigure_ind(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean delayreport_ind(struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t rseid, uint16_t delay,
+ uint8_t *err, void *user_data)
+{
+ printf("%s\n", __func__);
+
+ if (reject)
+ return FALSE;
+
+ return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+ .get_capability = get_capability_ind,
+ .set_configuration = set_configuration_ind,
+ .get_configuration = get_configuration_ind,
+ .open = open_ind,
+ .close = close_ind,
+ .start = start_ind,
+ .suspend = suspend_ind,
+ .abort = abort_ind,
+ .reconfigure = reconfigure_ind,
+ .delayreport = delayreport_ind,
+};
+
+static void usage(void)
+{
+ printf("avdtptest - AVDTP testing ver %s\n", VERSION);
+ printf("Usage:\n"
+ "\tavdtptest [options]\n");
+ printf("options:\n"
+ "\t-d <device_role> SRC (source) or SINK (sink)\n"
+ "\t-i <hcidev> HCI adapter\n"
+ "\t-c <bdaddr> connect\n"
+ "\t-l listen\n"
+ "\t-r reject commands\n"
+ "\t-f fragment\n"
+ "\t-p configure stream\n"
+ "\t-s <command> send command\n"
+ "\t-v <version> set version (0x0100, 0x0102, 0x0103\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device_role", 1, 0, 'd' },
+ { "adapter", 1, 0, 'i' },
+ { "connect", 1, 0, 'c' },
+ { "listen", 0, 0, 'l' },
+ { "reject", 0, 0, 'r' },
+ { "fragment", 0, 0, 'f' },
+ { "preconf", 0, 0, 'p' },
+ { "send", 1, 0, 's' },
+ { "version", 1, 0, 'v' },
+ { 0, 0, 0, 0 }
+};
+
+static GIOChannel *do_listen(GError **err)
+{
+ if (fragment)
+ return bt_io_listen(connect_cb, NULL, NULL, NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_MTU, 48,
+ BT_IO_OPT_INVALID);
+
+ return bt_io_listen(connect_cb, NULL, NULL, NULL, err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_PSM, AVDTP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+}
+
+int main(int argc, char *argv[])
+{
+ GError *err = NULL;
+ int opt;
+
+ bacpy(&src, BDADDR_ANY);
+ bacpy(&dst, BDADDR_ANY);
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ if (!mainloop) {
+ printf("Failed to create main loop\n");
+
+ exit(1);
+ }
+
+ while ((opt = getopt_long(argc, argv, "d:hi:s:c:v:lrfp",
+ main_options, NULL)) != EOF) {
+ switch (opt) {
+ case 'i':
+ if (!strncmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &src);
+ else
+ str2ba(optarg, &src);
+ break;
+ case 'd':
+ if (!strncasecmp(optarg, "SRC", sizeof("SRC"))) {
+ dev_role = AVDTP_SEP_TYPE_SOURCE;
+ } else if (!strncasecmp(optarg, "SINK",
+ sizeof("SINK"))) {
+ dev_role = AVDTP_SEP_TYPE_SINK;
+ } else {
+ usage();
+ exit(1);
+ }
+ break;
+ case 'c':
+ if (str2ba(optarg, &dst) < 0) {
+ usage();
+ exit(1);
+ }
+ break;
+ case 'l':
+ bacpy(&dst, BDADDR_ANY);
+ break;
+ case 'r':
+ reject = true;
+ break;
+ case 'f':
+ fragment = true;
+ break;
+ case 'p':
+ preconf = true;
+ break;
+ case 's':
+ parse_command(optarg);
+ break;
+ case 'v':
+ version = strtol(optarg, NULL, 0);
+ if (version != 0x0100 && version != 0x0102 &&
+ version != 0x0103) {
+ printf("invalid version\n");
+ exit(1);
+ }
+
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ lseps = queue_new();
+
+ local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, TRUE, &sep_ind, &sep_cfm, NULL);
+ if (!local_sep) {
+ printf("Failed to register sep\n");
+ exit(1);
+ }
+
+ queue_push_tail(lseps, local_sep);
+
+ if (!bacmp(&dst, BDADDR_ANY)) {
+ printf("Listening...\n");
+ io = do_listen(&err);
+ } else {
+ printf("Connecting...\n");
+ io = do_connect(&err);
+ }
+
+ if (!io) {
+ printf("Failed: %s\n", err->message);
+ g_error_free(err);
+ exit(1);
+ }
+
+ g_main_loop_run(mainloop);
+
+ printf("Done\n");
+
+ queue_destroy(lseps, NULL);
+
+ avdtp_unref(avdtp);
+ avdtp = NULL;
+
+ g_main_loop_unref(mainloop);
+ mainloop = NULL;
+
+ return 0;
+}
diff --git a/repo/android/avrcp-lib.c b/repo/android/avrcp-lib.c
new file mode 100644
index 0000000..4edfd0e
--- /dev/null
+++ b/repo/android/avrcp-lib.c
@@ -0,0 +1,3615 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+
+/* Packet types */
+#define AVRCP_PACKET_TYPE_SINGLE 0x00
+#define AVRCP_PACKET_TYPE_START 0x01
+#define AVRCP_PACKET_TYPE_CONTINUING 0x02
+#define AVRCP_PACKET_TYPE_END 0x03
+
+#define AVRCP_CHARSET_UTF8 0x006a
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t packet_type:2;
+ uint8_t rsvd:6;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t rsvd:6;
+ uint8_t packet_type:2;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
+struct get_capabilities_req {
+ uint8_t cap;
+ uint8_t params[0];
+} __attribute__ ((packed));
+
+struct get_capabilities_rsp {
+ uint8_t cap;
+ uint8_t number;
+ uint8_t params[0];
+} __attribute__ ((packed));
+
+struct list_attributes_rsp {
+ uint8_t number;
+ uint8_t params[0];
+} __attribute__ ((packed));
+
+struct list_values_req {
+ uint8_t attr;
+} __attribute__ ((packed));
+
+struct list_values_rsp {
+ uint8_t number;
+ uint8_t params[0];
+} __attribute__ ((packed));
+
+struct get_value_req {
+ uint8_t number;
+ uint8_t attrs[0];
+} __attribute__ ((packed));
+
+struct attr_value {
+ uint8_t attr;
+ uint8_t value;
+} __attribute__ ((packed));
+
+struct value_rsp {
+ uint8_t number;
+ struct attr_value values[0];
+} __attribute__ ((packed));
+
+struct set_value_req {
+ uint8_t number;
+ struct attr_value values[0];
+} __attribute__ ((packed));
+
+struct get_attribute_text_req {
+ uint8_t number;
+ uint8_t attrs[0];
+} __attribute__ ((packed));
+
+struct text_value {
+ uint8_t attr;
+ uint16_t charset;
+ uint8_t len;
+ char data[0];
+} __attribute__ ((packed));
+
+struct get_attribute_text_rsp {
+ uint8_t number;
+ struct text_value values[0];
+} __attribute__ ((packed));
+
+struct get_value_text_req {
+ uint8_t attr;
+ uint8_t number;
+ uint8_t values[0];
+} __attribute__ ((packed));
+
+struct get_value_text_rsp {
+ uint8_t number;
+ struct text_value values[0];
+} __attribute__ ((packed));
+
+struct media_item {
+ uint32_t attr;
+ uint16_t charset;
+ uint16_t len;
+ char data[0];
+} __attribute__ ((packed));
+
+struct get_element_attributes_req {
+ uint64_t id;
+ uint8_t number;
+ uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_element_attributes_rsp {
+ uint8_t number;
+ struct media_item items[0];
+} __attribute__ ((packed));
+
+struct get_play_status_rsp {
+ uint32_t duration;
+ uint32_t position;
+ uint8_t status;
+} __attribute__ ((packed));
+
+struct register_notification_req {
+ uint8_t event;
+ uint32_t interval;
+} __attribute__ ((packed));
+
+struct register_notification_rsp {
+ uint8_t event;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct set_volume_req {
+ uint8_t value;
+} __attribute__ ((packed));
+
+struct set_volume_rsp {
+ uint8_t value;
+} __attribute__ ((packed));
+
+struct set_addressed_req {
+ uint16_t id;
+} __attribute__ ((packed));
+
+struct set_addressed_rsp {
+ uint8_t status;
+} __attribute__ ((packed));
+
+struct set_browsed_req {
+ uint16_t id;
+} __attribute__ ((packed));
+
+struct set_browsed_rsp {
+ uint8_t status;
+ uint16_t counter;
+ uint32_t items;
+ uint16_t charset;
+ uint8_t depth;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct get_folder_items_req {
+ uint8_t scope;
+ uint32_t start;
+ uint32_t end;
+ uint8_t number;
+ uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_folder_items_rsp {
+ uint8_t status;
+ uint16_t counter;
+ uint16_t number;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct change_path_req {
+ uint16_t counter;
+ uint8_t direction;
+ uint64_t uid;
+} __attribute__ ((packed));
+
+struct change_path_rsp {
+ uint8_t status;
+ uint32_t items;
+} __attribute__ ((packed));
+
+struct get_item_attributes_req {
+ uint8_t scope;
+ uint64_t uid;
+ uint16_t counter;
+ uint8_t number;
+ uint32_t attrs[0];
+} __attribute__ ((packed));
+
+struct get_item_attributes_rsp {
+ uint8_t status;
+ uint8_t number;
+ struct media_item items[0];
+} __attribute__ ((packed));
+
+struct play_item_req {
+ uint8_t scope;
+ uint64_t uid;
+ uint16_t counter;
+} __attribute__ ((packed));
+
+struct play_item_rsp {
+ uint8_t status;
+} __attribute__ ((packed));
+
+struct search_req {
+ uint16_t charset;
+ uint16_t len;
+ char string[0];
+} __attribute__ ((packed));
+
+struct search_rsp {
+ uint8_t status;
+ uint16_t counter;
+ uint32_t items;
+} __attribute__ ((packed));
+
+struct add_to_now_playing_req {
+ uint8_t scope;
+ uint64_t uid;
+ uint16_t counter;
+} __attribute__ ((packed));
+
+struct add_to_now_playing_rsp {
+ uint8_t status;
+} __attribute__ ((packed));
+
+struct avrcp_control_handler {
+ uint8_t id;
+ uint8_t code;
+ uint8_t rsp;
+ ssize_t (*func) (struct avrcp *session, uint8_t transaction,
+ uint16_t params_len, uint8_t *params, void *user_data);
+};
+
+struct avrcp_browsing_handler {
+ uint8_t id;
+ ssize_t (*func) (struct avrcp *session, uint8_t transaction,
+ uint16_t params_len, uint8_t *params, void *user_data);
+};
+
+struct avrcp_continuing {
+ uint8_t pdu_id;
+ struct iovec pdu;
+};
+
+struct avrcp {
+ struct avctp *conn;
+ struct avrcp_player *player;
+
+ const struct avrcp_control_handler *control_handlers;
+ void *control_data;
+ unsigned int control_id;
+ uint16_t control_mtu;
+
+ struct avrcp_continuing *continuing;
+
+ const struct avrcp_passthrough_handler *passthrough_handlers;
+ void *passthrough_data;
+ unsigned int passthrough_id;
+
+ const struct avrcp_browsing_handler *browsing_handlers;
+ void *browsing_data;
+ unsigned int browsing_id;
+
+ avrcp_destroy_cb_t destroy;
+ void *destroy_data;
+};
+
+struct avrcp_player {
+ const struct avrcp_control_ind *ind;
+ const struct avrcp_control_cfm *cfm;
+
+ void *user_data;
+};
+
+static inline uint32_t ntoh24(const uint8_t src[3])
+{
+ return src[0] << 16 | src[1] << 8 | src[2];
+}
+
+static inline void hton24(uint8_t dst[3], uint32_t src)
+{
+ dst[0] = (src & 0xff0000) >> 16;
+ dst[1] = (src & 0x00ff00) >> 8;
+ dst[2] = (src & 0x0000ff);
+}
+