mirror of
https://github.com/IllusionMan1212/ShockPair.git
synced 2026-10-23 18:12:26 +00:00
initial commit
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
|
||||
# bluetooth shared libs dir
|
||||
app/src/main/btLibs
|
||||
Generated
+3
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="1.8" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 IllusionMan1212
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,71 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.2"
|
||||
android.ndkVersion = "21.3.6528147"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.illusionware.shockpair"
|
||||
minSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
useIR = true
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path file('src/main/c/CMakeLists.txt')
|
||||
version "3.10.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||
implementation "com.github.topjohnwu.libsu:service:3.1.2"
|
||||
testImplementation 'junit:junit:4.+'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
||||
|
||||
// function to run before the build starts.
|
||||
// this function runs the ndk-build binary on the bluez bluetooth lib to build the shared lib
|
||||
task runNdkBuild(type: Exec) {
|
||||
def ndkDir = android.ndkDirectory
|
||||
executable = "$ndkDir/ndk-build"
|
||||
args = ['NDK_PROJECT_PATH=build/intermediates/ndk',
|
||||
'NDK_LIBS_OUT=src/main/btLibs',
|
||||
'APP_BUILD_SCRIPT=src/main/c/bluez-android-3.35/libs/Android.mk']
|
||||
}
|
||||
|
||||
// tell gradle to run the function before the build
|
||||
preBuild.dependsOn runNdkBuild
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.illusionware.shockpair
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.illusionware.shockpair", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.illusionware.shockpair">
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
|
||||
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
|
||||
|
||||
<uses-feature android:name="android.hardware.bluetooth" />
|
||||
|
||||
<application
|
||||
android:debuggable="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.ShockPair">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,10 @@
|
||||
// IRootService.aidl
|
||||
package com.illusionware.shockpair;
|
||||
|
||||
// Declare any non-default types here with import statements
|
||||
|
||||
interface IRootService {
|
||||
int getPid();
|
||||
int getUid();
|
||||
int connectToDS3();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
add_library( # Sets the name of the library.
|
||||
shockpairdriver-lib
|
||||
|
||||
# Sets the library as a shared library.
|
||||
SHARED
|
||||
|
||||
# Provides a relative path to your source file(s).
|
||||
shockpairdriver.c)
|
||||
|
||||
# Searches for a specified prebuilt library and stores the path as a
|
||||
# variable. Because CMake includes system libraries in the search path by
|
||||
# default, you only need to specify the name of the public NDK library
|
||||
# you want to add. CMake verifies that the library exists before
|
||||
# completing its build.
|
||||
|
||||
find_library( # Sets the name of the path variable.
|
||||
log-lib
|
||||
|
||||
# Specifies the name of the NDK library that
|
||||
# you want CMake to locate.
|
||||
log )
|
||||
|
||||
# include the headers directory for the bluez lib
|
||||
include_directories(bluez-android-3.35/libs/include)
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You
|
||||
# can link multiple libraries, such as libraries you define in this
|
||||
# build script, prebuilt third-party libraries, or system libraries.
|
||||
|
||||
target_link_libraries( # Specifies the target library.
|
||||
shockpairdriver-lib
|
||||
|
||||
# link the bluez shared lib to our driver for each ABI
|
||||
${PROJECT_SOURCE_DIR}/../btLibs/${ANDROID_ABI}/libbluetooth.so
|
||||
# Links the target library to the log library
|
||||
# included in the NDK.
|
||||
${log-lib})
|
||||
@@ -0,0 +1,109 @@
|
||||
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 <brian.gix@intel.com>
|
||||
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@codecoup.pl>
|
||||
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>
|
||||
Michał Narajowski <michal.narajowski@codecoup.pl>
|
||||
Inga Stotland <inga.stotland@intel.com>
|
||||
Alain Michaud <alainm@chromium.org>
|
||||
Robert Lubaś <robert.lubas@silvair.com>
|
||||
Michał Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>
|
||||
Jakub Witowski <jakub.witowski@silvair.com>
|
||||
Rafał Gajda <rafal.gajda@silvair.com>
|
||||
Szymon Czapracki <szymon.czapracki@codecoup.pl>
|
||||
@@ -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.
|
||||
@@ -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!
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
|
||||
@@ -0,0 +1,699 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
AM_MAKEFLAGS = --no-print-directory
|
||||
AM_CPPFLAGS =
|
||||
|
||||
lib_LTLIBRARIES =
|
||||
|
||||
noinst_LIBRARIES =
|
||||
|
||||
noinst_LTLIBRARIES =
|
||||
|
||||
bin_PROGRAMS =
|
||||
|
||||
noinst_PROGRAMS =
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
pkglibexecdir = $(libexecdir)/bluetooth
|
||||
|
||||
pkglibexec_PROGRAMS =
|
||||
|
||||
pkgincludedir = $(includedir)/bluetooth
|
||||
|
||||
pkginclude_HEADERS =
|
||||
|
||||
AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) $(UDEV_CFLAGS) $(ell_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
|
||||
|
||||
if MANPAGES
|
||||
man_MANS =
|
||||
endif
|
||||
manual_pages =
|
||||
|
||||
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) $(ell_built_sources) src/builtin.h
|
||||
|
||||
if LIBRARY
|
||||
pkginclude_HEADERS += $(lib_headers)
|
||||
|
||||
lib_LTLIBRARIES += lib/libbluetooth.la
|
||||
|
||||
lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
|
||||
lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 22:5:19
|
||||
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
|
||||
|
||||
if EXTERNAL_ELL
|
||||
ell_cflags = @ELL_CFLAGS@
|
||||
ell_ldadd = @ELL_LIBS@
|
||||
ell_dependencies =
|
||||
ell_built_sources = ell/shared
|
||||
else
|
||||
ell_cflags =
|
||||
ell_ldadd = ell/libell-internal.la
|
||||
ell_dependencies = $(ell_ldadd)
|
||||
ell_built_sources = ell/shared ell/internal ell/ell.h
|
||||
|
||||
noinst_LTLIBRARIES += ell/libell-internal.la
|
||||
|
||||
ell_headers = ell/util.h \
|
||||
ell/log.h \
|
||||
ell/queue.h \
|
||||
ell/hashmap.h \
|
||||
ell/random.h \
|
||||
ell/signal.h \
|
||||
ell/time.h \
|
||||
ell/time-private.h \
|
||||
ell/timeout.h \
|
||||
ell/cipher.h \
|
||||
ell/checksum.h \
|
||||
ell/io.h \
|
||||
ell/idle.h \
|
||||
ell/main.h \
|
||||
ell/settings.h \
|
||||
ell/strv.h \
|
||||
ell/string.h \
|
||||
ell/utf8.h \
|
||||
ell/dbus.h \
|
||||
ell/dbus-service.h \
|
||||
ell/dbus-client.h \
|
||||
ell/key.h \
|
||||
ell/cert.h \
|
||||
ell/pem.h \
|
||||
ell/base64.h \
|
||||
ell/asn1-private.h \
|
||||
ell/cert-private.h \
|
||||
ell/pem-private.h \
|
||||
ell/uuid.h \
|
||||
ell/useful.h \
|
||||
ell/main-private.h \
|
||||
ell/tester.h \
|
||||
ell/tls.h \
|
||||
ell/tls-private.h \
|
||||
ell/ecc.h \
|
||||
ell/ecc-private.h \
|
||||
ell/ecdh.h
|
||||
|
||||
ell_sources = ell/private.h ell/missing.h \
|
||||
ell/util.c \
|
||||
ell/log.c \
|
||||
ell/queue.c \
|
||||
ell/hashmap.c \
|
||||
ell/random.c \
|
||||
ell/signal.c \
|
||||
ell/time.c \
|
||||
ell/timeout.c \
|
||||
ell/io.c \
|
||||
ell/idle.c \
|
||||
ell/main.c \
|
||||
ell/settings.c \
|
||||
ell/strv.c \
|
||||
ell/string.c \
|
||||
ell/cipher.c \
|
||||
ell/checksum.c \
|
||||
ell/pem.c \
|
||||
ell/cert.c \
|
||||
ell/cert-crypto.c \
|
||||
ell/key.c \
|
||||
ell/base64.c \
|
||||
ell/utf8.c \
|
||||
ell/dbus-private.h \
|
||||
ell/dbus.c \
|
||||
ell/dbus-message.c \
|
||||
ell/dbus-util.c \
|
||||
ell/dbus-service.c \
|
||||
ell/dbus-client.c \
|
||||
ell/dbus-name-cache.c \
|
||||
ell/dbus-filter.c \
|
||||
ell/gvariant-private.h \
|
||||
ell/gvariant-util.c \
|
||||
ell/siphash-private.h \
|
||||
ell/siphash.c \
|
||||
ell/uuid.c \
|
||||
ell/tester.c \
|
||||
ell/tls.c \
|
||||
ell/tls-extensions.c \
|
||||
ell/tls-suites.c \
|
||||
ell/tls-record.c \
|
||||
ell/ecc.c \
|
||||
ell/ecc-external.c \
|
||||
ell/ecdh.c
|
||||
|
||||
ell_shared = ell/useful.h
|
||||
|
||||
ell_libell_internal_la_SOURCES = $(ell_headers) $(ell_sources) $(ell_shared)
|
||||
endif
|
||||
|
||||
CLEANFILES += $(ell_built_sources)
|
||||
|
||||
noinst_LTLIBRARIES += src/libshared-glib.la src/libshared-mainloop.la
|
||||
|
||||
if LIBSHARED_ELL
|
||||
noinst_LTLIBRARIES += src/libshared-ell.la
|
||||
endif
|
||||
|
||||
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/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/shared/log.h src/shared/log.c \
|
||||
src/shared/tty.h
|
||||
|
||||
if READLINE
|
||||
shared_sources += src/shared/shell.c src/shared/shell.h
|
||||
endif
|
||||
|
||||
src_libshared_glib_la_SOURCES = $(shared_sources) \
|
||||
src/shared/io-glib.c \
|
||||
src/shared/timeout-glib.c \
|
||||
src/shared/mainloop-glib.c \
|
||||
src/shared/mainloop-notify.h \
|
||||
src/shared/mainloop-notify.c \
|
||||
src/shared/tester.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 \
|
||||
src/shared/mainloop-notify.h \
|
||||
src/shared/mainloop-notify.c
|
||||
|
||||
if LIBSHARED_ELL
|
||||
src_libshared_ell_la_SOURCES = $(shared_sources) \
|
||||
src/shared/io-ell.c \
|
||||
src/shared/timeout-ell.c \
|
||||
src/shared/mainloop.h \
|
||||
src/shared/mainloop-ell.c
|
||||
endif
|
||||
|
||||
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_cppflags =
|
||||
builtin_nodist =
|
||||
builtin_ldadd =
|
||||
|
||||
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
|
||||
|
||||
pkglibexec_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/rfkill.c src/btd.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/dbus-common.c src/dbus-common.h \
|
||||
src/eir.h src/eir.c \
|
||||
src/adv_monitor.h src/adv_monitor.c \
|
||||
src/battery.h src/battery.c
|
||||
src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
|
||||
gdbus/libgdbus-internal.la \
|
||||
src/libshared-glib.la \
|
||||
$(BACKTRACE_LIBS) $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt \
|
||||
$(builtin_ldadd)
|
||||
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_CPPFLAGS = $(AM_CPPFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
|
||||
-DPLUGINDIR=\""$(build_plugindir)"\" \
|
||||
$(BACKTRACE_CFLAGS) $(builtin_cppflags)
|
||||
src_bluetoothd_SHORTNAME = bluetoothd
|
||||
|
||||
builtin_files = src/builtin.h $(builtin_nodist)
|
||||
|
||||
nodist_src_bluetoothd_SOURCES = $(builtin_files)
|
||||
|
||||
CLEANFILES += $(builtin_files) src/bluetooth.service
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += src/bluetoothd.8
|
||||
endif
|
||||
manual_pages += src/bluetoothd.8
|
||||
|
||||
EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
|
||||
src/main.conf profiles/network/network.conf \
|
||||
profiles/input/input.conf
|
||||
|
||||
test_scripts =
|
||||
unit_tests =
|
||||
|
||||
include Makefile.tools
|
||||
include Makefile.obexd
|
||||
include android/Makefile.am
|
||||
include Makefile.mesh
|
||||
|
||||
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/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 += doc/btsnoop.txt
|
||||
|
||||
EXTRA_DIST += tools/magic.btsnoop
|
||||
|
||||
AM_CPPFLAGS += $(DBUS_CFLAGS) $(GLIB_CFLAGS) -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)
|
||||
|
||||
if OBEX
|
||||
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)
|
||||
endif
|
||||
|
||||
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 MIDI
|
||||
unit_tests += unit/test-midi
|
||||
unit_test_midi_CPPFLAGS = $(AM_CPPFLAGS) $(ALSA_CFLAGS) -DMIDI_TEST
|
||||
unit_test_midi_SOURCES = unit/test-midi.c \
|
||||
profiles/midi/libmidi.h \
|
||||
profiles/midi/libmidi.c
|
||||
unit_test_midi_LDADD = src/libshared-glib.la \
|
||||
$(GLIB_LIBS) $(ALSA_LIBS)
|
||||
endif
|
||||
|
||||
if MESH
|
||||
unit_tests += unit/test-mesh-crypto
|
||||
unit_test_mesh_crypto_CPPFLAGS = $(ell_cflags)
|
||||
unit_test_mesh_crypto_SOURCES = unit/test-mesh-crypto.c \
|
||||
mesh/crypto.h ell/internal ell/ell.h
|
||||
unit_test_mesh_crypto_LDADD = $(ell_ldadd)
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
EXTRA_DIST += $(manual_pages) $(patsubst %.1,%.rst, \
|
||||
$(patsubst %.8,%.rst,$(manual_pages)))
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \
|
||||
--enable-health \
|
||||
--enable-midi \
|
||||
--enable-manpages \
|
||||
--enable-android \
|
||||
--enable-mesh \
|
||||
--enable-btpclient \
|
||||
--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,@pkglibexecdir\@,$(pkglibexecdir),g' \
|
||||
< $< > $@
|
||||
|
||||
if RUN_RST2MAN
|
||||
RST2MAN_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
|
||||
$(RST2MAN) --strict --no-raw \
|
||||
--no-generator --no-datestamp $< $@
|
||||
else
|
||||
RST2MAN_PROCESS = $(AM_V_GEN)test -f $@ || \
|
||||
{ echo "Generated manual page $@ does not exist"; false; }
|
||||
endif
|
||||
|
||||
%.service: %.service.in Makefile
|
||||
$(SED_PROCESS)
|
||||
|
||||
%.1: %.rst Makefile
|
||||
$(RST2MAN_PROCESS)
|
||||
|
||||
%.8: %.rst Makefile
|
||||
$(RST2MAN_PROCESS)
|
||||
|
||||
src/builtin.h: src/genbuiltin $(builtin_sources)
|
||||
$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
|
||||
|
||||
tools/%.rules:
|
||||
$(AM_V_at)$(MKDIR_P) tools
|
||||
$(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 $(abspath $<) $@
|
||||
|
||||
ell/shared: Makefile
|
||||
$(AM_V_at)$(MKDIR_P) ell
|
||||
$(AM_V_GEN)for f in $(ell_shared) ; do \
|
||||
if [ ! -f $$f ] ; then \
|
||||
$(LN_S) -t ell -f $(abs_srcdir)/../ell/$$f ; \
|
||||
fi \
|
||||
done > $@
|
||||
|
||||
ell/internal: Makefile
|
||||
$(AM_V_at)$(MKDIR_P) ell
|
||||
$(AM_V_GEN)for f in $(ell_headers) $(ell_sources) ; do \
|
||||
if [ ! -f $$f ] ; then \
|
||||
$(LN_S) -t ell -f $(abs_srcdir)/../ell/$$f ; \
|
||||
fi \
|
||||
done > $@
|
||||
|
||||
ell/ell.h: Makefile
|
||||
$(AM_V_at)echo -n > $@
|
||||
$(AM_V_GEN)for f in $(ell_headers) ; do \
|
||||
echo "#include <$$f>" >> $@ ; \
|
||||
done
|
||||
|
||||
maintainer-clean-local:
|
||||
-rm -rf ell
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
if MESH
|
||||
|
||||
if DATAFILES
|
||||
dbus_DATA += mesh/bluetooth-mesh.conf
|
||||
endif
|
||||
|
||||
if SYSTEMD
|
||||
systemdsystemunit_DATA += mesh/bluetooth-mesh.service
|
||||
dbussystembus_DATA += mesh/org.bluez.mesh.service
|
||||
endif
|
||||
|
||||
mesh_sources = mesh/mesh.h mesh/mesh.c \
|
||||
mesh/net-keys.h mesh/net-keys.c \
|
||||
mesh/mesh-io.h mesh/mesh-io.c \
|
||||
mesh/mesh-mgmt.c mesh/mesh-mgmt.h \
|
||||
mesh/error.h mesh/mesh-io-api.h \
|
||||
mesh/mesh-io-generic.h \
|
||||
mesh/mesh-io-generic.c \
|
||||
mesh/mesh-io-unit.h \
|
||||
mesh/mesh-io-unit.c \
|
||||
mesh/net.h mesh/net.c \
|
||||
mesh/crypto.h mesh/crypto.c \
|
||||
mesh/friend.h mesh/friend.c \
|
||||
mesh/appkey.h mesh/appkey.c \
|
||||
mesh/node.h mesh/node.c \
|
||||
mesh/provision.h mesh/prov.h \
|
||||
mesh/model.h mesh/model.c \
|
||||
mesh/cfgmod.h mesh/cfgmod-server.c \
|
||||
mesh/mesh-config.h mesh/mesh-config-json.c \
|
||||
mesh/util.h mesh/util.c \
|
||||
mesh/dbus.h mesh/dbus.c \
|
||||
mesh/agent.h mesh/agent.c \
|
||||
mesh/prov-acceptor.c mesh/prov-initiator.c \
|
||||
mesh/manager.h mesh/manager.c \
|
||||
mesh/pb-adv.h mesh/pb-adv.c \
|
||||
mesh/keyring.h mesh/keyring.c \
|
||||
mesh/rpl.h mesh/rpl.c \
|
||||
mesh/mesh-defs.h
|
||||
pkglibexec_PROGRAMS += mesh/bluetooth-meshd
|
||||
|
||||
mesh/mesh.$(OBJEXT): ell/internal
|
||||
mesh/main.$(OBJEXT): src/builtin.h lib/bluetooth/bluetooth.h
|
||||
|
||||
mesh_bluetooth_meshd_SOURCES = $(mesh_sources) mesh/main.c
|
||||
mesh_bluetooth_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c
|
||||
mesh_bluetooth_meshd_DEPENDENCIES = $(ell_dependencies) src/libshared-ell.la \
|
||||
mesh/bluetooth-mesh.service
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += mesh/bluetooth-meshd.8
|
||||
endif
|
||||
manual_pages += mesh/bluetooth-meshd.8
|
||||
|
||||
CLEANFILES += mesh/bluetooth-mesh.service
|
||||
|
||||
endif
|
||||
|
||||
EXTRA_DIST += mesh/bluetooth-mesh.conf mesh/bluetooth-mesh.service.in \
|
||||
mesh/org.bluez.mesh.service mesh/mesh-main.conf
|
||||
@@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
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
|
||||
|
||||
if OBEX
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
pkglibexec_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/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 = $(AM_LDFLAGS) -Wl,--export-dynamic
|
||||
|
||||
obexd_src_obexd_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \
|
||||
$(ICAL_CFLAGS) -DOBEX_PLUGIN_BUILTIN \
|
||||
-DPLUGINDIR=\""$(obex_plugindir)"\" \
|
||||
-D_FILE_OFFSET_BITS=64 \
|
||||
-I$(builddir)/lib -I$(builddir)/obexd/src
|
||||
|
||||
obexd_src_obexd_CFLAGS = $(AM_CFLAGS) -fPIC
|
||||
|
||||
endif
|
||||
|
||||
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_at)$(MKDIR_P) $(dir $@)
|
||||
$(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
|
||||
@@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
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 NFC
|
||||
builtin_modules += neard
|
||||
builtin_sources += plugins/neard.c
|
||||
endif
|
||||
|
||||
if SAP
|
||||
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
|
||||
endif
|
||||
|
||||
if A2DP
|
||||
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
|
||||
endif
|
||||
|
||||
|
||||
if AVRCP
|
||||
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
|
||||
endif
|
||||
|
||||
if NETWORK
|
||||
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
|
||||
endif
|
||||
|
||||
if HID
|
||||
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 profiles/input/sixaxis.h
|
||||
endif
|
||||
|
||||
if HOG
|
||||
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
|
||||
endif
|
||||
|
||||
if HEALTH
|
||||
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 MIDI
|
||||
builtin_modules += midi
|
||||
builtin_sources += profiles/midi/midi.c \
|
||||
profiles/midi/libmidi.h \
|
||||
profiles/midi/libmidi.c
|
||||
builtin_cppflags += $(ALSA_CFLAGS)
|
||||
builtin_ldadd += $(ALSA_LIBS)
|
||||
endif
|
||||
|
||||
builtin_modules += battery
|
||||
builtin_sources += profiles/battery/battery.c
|
||||
|
||||
if SIXAXIS
|
||||
plugin_LTLIBRARIES += plugins/sixaxis.la
|
||||
plugins_sixaxis_la_SOURCES = plugins/sixaxis.c
|
||||
plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
|
||||
plugins_sixaxis_la_LIBADD = $(UDEV_LIBS)
|
||||
plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
|
||||
endif
|
||||
@@ -0,0 +1,515 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
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/advertising.h \
|
||||
client/advertising.c \
|
||||
client/adv_monitor.h \
|
||||
client/adv_monitor.c \
|
||||
client/gatt.h client/gatt.c
|
||||
client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
|
||||
$(GLIB_LIBS) $(DBUS_LIBS) -lreadline
|
||||
endif
|
||||
|
||||
if ZSH_COMPLETIONS
|
||||
zshcompletiondir=$(ZSH_COMPLETIONDIR)
|
||||
dist_zshcompletion_DATA = completion/zsh/_bluetoothctl
|
||||
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/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/msft.h monitor/msft.c \
|
||||
monitor/jlink.h monitor/jlink.c \
|
||||
monitor/tty.h
|
||||
monitor_btmon_LDADD = lib/libbluetooth-internal.la \
|
||||
src/libshared-mainloop.la $(UDEV_LIBS) -ldl
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += monitor/btmon.1
|
||||
endif
|
||||
endif
|
||||
manual_pages += monitor/btmon.1
|
||||
|
||||
if LOGGER
|
||||
pkglibexec_PROGRAMS += tools/btmon-logger
|
||||
|
||||
tools_btmon_logger_SOURCES = tools/btmon-logger.c
|
||||
tools_btmon_logger_LDADD = src/libshared-mainloop.la
|
||||
tools_btmon_logger_DEPENDENCIES = src/libshared-mainloop.la \
|
||||
tools/bluetooth-logger.service
|
||||
|
||||
if SYSTEMD
|
||||
systemdsystemunit_DATA += tools/bluetooth-logger.service
|
||||
endif
|
||||
endif
|
||||
|
||||
CLEANFILES += tools/bluetooth-logger.service
|
||||
EXTRA_DIST += tools/bluetooth-logger.service.in
|
||||
|
||||
if TESTING
|
||||
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/rctest tools/l2test tools/l2ping tools/bluemoon \
|
||||
tools/hex2hcd tools/mpris-proxy tools/btattach
|
||||
|
||||
noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
|
||||
tools/scotest tools/amptest tools/hwdb \
|
||||
tools/hcieventmask tools/hcisecfilter \
|
||||
tools/btinfo tools/btconfig \
|
||||
tools/btsnoop tools/btproxy \
|
||||
tools/btiotest tools/bneptest tools/mcaptest \
|
||||
tools/cltest tools/oobtest tools/advtest \
|
||||
tools/seq2bseq tools/nokfw tools/rtlfw \
|
||||
tools/bcmfw tools/create-image \
|
||||
tools/eddystone tools/ibeacon \
|
||||
tools/btgatt-client tools/btgatt-server \
|
||||
tools/test-runner tools/check-selftest \
|
||||
tools/gatt-service profiles/iap/iapd
|
||||
|
||||
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_btconfig_SOURCES = tools/btconfig.c
|
||||
tools_btconfig_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) \
|
||||
src/libshared-mainloop.la -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) \
|
||||
src/libshared-mainloop.la
|
||||
|
||||
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_advtest_SOURCES = tools/advtest.c
|
||||
tools_advtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
|
||||
|
||||
tools_seq2bseq_SOURCES = tools/seq2bseq.c
|
||||
|
||||
tools_nokfw_SOURCES = tools/nokfw.c
|
||||
|
||||
tools_rtlfw_SOURCES = tools/rtlfw.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
|
||||
|
||||
tools_rctest_LDADD = lib/libbluetooth-internal.la
|
||||
|
||||
tools_l2test_LDADD = lib/libbluetooth-internal.la
|
||||
|
||||
tools_l2ping_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)
|
||||
|
||||
tools_gatt_service_SOURCES = tools/gatt-service.c
|
||||
tools_gatt_service_LDADD = $(GLIB_LIBS) $(DBUS_LIBS) gdbus/libgdbus-internal.la
|
||||
|
||||
profiles_iap_iapd_SOURCES = profiles/iap/main.c
|
||||
profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS)
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += tools/rctest.1 tools/l2ping.1 tools/btattach.1
|
||||
endif
|
||||
|
||||
if MESH
|
||||
bin_PROGRAMS += tools/meshctl
|
||||
|
||||
tools_meshctl_SOURCES = tools/meshctl.c \
|
||||
tools/mesh/agent.h tools/mesh/agent.c \
|
||||
tools/mesh/config-model.h\
|
||||
tools/mesh-gatt/mesh-net.h \
|
||||
tools/mesh-gatt/node.h tools/mesh-gatt/node.c \
|
||||
tools/mesh-gatt/gatt.h tools/mesh-gatt/gatt.c \
|
||||
tools/mesh-gatt/crypto.h\
|
||||
tools/mesh-gatt/crypto.c \
|
||||
tools/mesh-gatt/keys.h \
|
||||
tools/mesh-gatt/net.h tools/mesh-gatt/net.c \
|
||||
tools/mesh-gatt/prov.h tools/mesh-gatt/prov.c \
|
||||
tools/mesh-gatt/util.h tools/mesh-gatt/util.c \
|
||||
tools/mesh-gatt/prov-db.h \
|
||||
tools/mesh-gatt/prov-db.c \
|
||||
tools/mesh-gatt/config-client.c \
|
||||
tools/mesh-gatt/config-server.c \
|
||||
tools/mesh-gatt/onoff-model.h \
|
||||
tools/mesh-gatt/onoff-model.c
|
||||
tools_meshctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
|
||||
lib/libbluetooth-internal.la \
|
||||
$(GLIB_LIBS) $(DBUS_LIBS) -ljson-c -lreadline
|
||||
|
||||
bin_PROGRAMS += tools/mesh-cfgclient
|
||||
|
||||
tools_mesh_cfgclient_SOURCES = tools/mesh-cfgclient.c \
|
||||
tools/mesh/model.h tools/mesh/config-model.h \
|
||||
tools/mesh/cfgcli.h tools/mesh/cfgcli.c \
|
||||
tools/mesh/keys.h tools/mesh/keys.c \
|
||||
tools/mesh/util.h tools/mesh/util.c \
|
||||
tools/mesh/remote.h tools/mesh/remote.c \
|
||||
tools/mesh/agent.h tools/mesh/agent.c \
|
||||
tools/mesh/mesh-db.h tools/mesh/mesh-db.c \
|
||||
mesh/util.h mesh/util.c \
|
||||
mesh/crypto.h mesh/crypto.c
|
||||
|
||||
tools_mesh_cfgclient_LDADD = lib/libbluetooth-internal.la src/libshared-ell.la \
|
||||
$(ell_ldadd) -ljson-c -lreadline
|
||||
|
||||
bin_PROGRAMS += tools/mesh-cfgtest
|
||||
|
||||
tools_mesh_cfgtest_SOURCES = tools/mesh-cfgtest.c
|
||||
tools_mesh_cfgtest_LDADD = lib/libbluetooth-internal.la src/libshared-ell.la \
|
||||
$(ell_ldadd)
|
||||
endif
|
||||
|
||||
EXTRA_DIST += tools/mesh-gatt/local_node.json tools/mesh-gatt/prov_db.json
|
||||
|
||||
if DEPRECATED
|
||||
bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
|
||||
tools/rfcomm tools/sdptool tools/ciptool
|
||||
|
||||
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_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_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_hcidump_LDADD = lib/libbluetooth-internal.la
|
||||
|
||||
tools_rfcomm_LDADD = lib/libbluetooth-internal.la
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += tools/hciattach.1 tools/hciconfig.1 \
|
||||
tools/hcitool.1 tools/hcidump.1 \
|
||||
tools/rfcomm.1 tools/sdptool.1 tools/ciptool.1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
manual_pages += tools/hciattach.1 tools/hciconfig.1 \
|
||||
tools/hcitool.1 tools/hcidump.1 \
|
||||
tools/rfcomm.1 tools/sdptool.1 tools/ciptool.1 \
|
||||
tools/rctest.1 tools/l2ping.1 tools/btattach.1 \
|
||||
tools/bdaddr.1
|
||||
|
||||
if HID2HCI
|
||||
udevdir = $(UDEV_DIR)
|
||||
|
||||
udev_PROGRAMS = tools/hid2hci
|
||||
|
||||
tools_hid2hci_LDADD = $(UDEV_LIBS)
|
||||
|
||||
if MANPAGES
|
||||
man_MANS += tools/hid2hci.1
|
||||
endif
|
||||
endif
|
||||
manual_pages += tools/hid2hci.1
|
||||
|
||||
if READLINE
|
||||
noinst_PROGRAMS += tools/btmgmt tools/obex-client-tool tools/obex-server-tool \
|
||||
tools/bluetooth-player tools/obexctl
|
||||
|
||||
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
|
||||
tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \
|
||||
src/libshared-glib.la \
|
||||
$(GLIB_LIBS) $(DBUS_LIBS) -lreadline
|
||||
|
||||
tools_obexctl_SOURCES = tools/obexctl.c
|
||||
tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.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
|
||||
if DEPRECATED
|
||||
noinst_PROGRAMS += attrib/gatttool
|
||||
|
||||
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
|
||||
|
||||
endif
|
||||
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-network 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-hfp 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 test/test-mesh test/agent.py
|
||||
|
||||
if BTPCLIENT
|
||||
noinst_PROGRAMS += tools/btpclient tools/btpclientctl
|
||||
|
||||
tools_btpclient_SOURCES = tools/btpclient.c src/shared/btp.c src/shared/btp.h
|
||||
tools_btpclient_LDADD = lib/libbluetooth-internal.la \
|
||||
src/libshared-ell.la $(ell_ldadd)
|
||||
tools_btpclient_DEPENDENCIES = lib/libbluetooth-internal.la $(ell_dependencies)
|
||||
tools/btpclient.$(OBJEXT): src/libshared-ell.la ell/internal
|
||||
|
||||
tools_btpclientctl_SOURCES = tools/btpclientctl.c client/display.c
|
||||
tools_btpclientctl_LDADD = src/libshared-mainloop.la src/libshared-glib.la \
|
||||
lib/libbluetooth-internal.la -lreadline
|
||||
endif
|
||||
@@ -0,0 +1,300 @@
|
||||
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)
|
||||
|
||||
On a debian based system, this can be done by running the following command:
|
||||
sudo apt-get build-dep bluez
|
||||
./bootstrap
|
||||
|
||||
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
|
||||
|
||||
|
||||
Embedded Linux library
|
||||
======================
|
||||
|
||||
In order to compile mesh support and test client utility the development
|
||||
version of Embedded Linux library is required to be present. The development
|
||||
repositories can be found here:
|
||||
|
||||
git://git.kernel.org/pub/scm/libs/ell/ell.git
|
||||
https://kernel.googlesource.com/pub/scm/libs/ell/ell.git
|
||||
|
||||
The build systems requires that the Embedded Linux library source code
|
||||
is available on the same top level directory as the source code:
|
||||
|
||||
.
|
||||
|--- ell
|
||||
| |--- ell
|
||||
| `--- unit
|
||||
`--- bluez
|
||||
|--- src
|
||||
`--- tools
|
||||
|
||||
It is not required to build or install Embedded Linux library. The build
|
||||
will happen when building the binaries and it will then be linked internally.
|
||||
|
||||
When using --enable-external-ell build option, it is not required that the
|
||||
Embedded Linux library source code is available in the top level directory.
|
||||
|
||||
When neither --enable-mesh nor --enable-btpclient is specified, then this
|
||||
part is irrelevant and Embedded Linux library is not required.
|
||||
|
||||
|
||||
Kernel Build Options (for Mesh)
|
||||
===============================
|
||||
|
||||
The Mesh daemon uses kernel provided crypto utilities to perform security
|
||||
functions required of Bluetooth Mesh. Many standard distributions currently
|
||||
enable all required crypto features, but a few notable distributions do
|
||||
not.
|
||||
|
||||
If Mesh Cryptography is not working, the following configuration options
|
||||
may need to be enabled, and the kernel rebuilt.
|
||||
|
||||
1. A minimum of kernel version 4.9 or later is required
|
||||
|
||||
2. The kernel must at a minimum have the following .config options turned on:
|
||||
CONFIG_CRYPTO_USER
|
||||
CONFIG_CRYPTO_USER_API
|
||||
CONFIG_CRYPTO_USER_API_AEAD
|
||||
CONFIG_CRYPTO_USER_API_HASH
|
||||
|
||||
CONFIG_CRYPTO_AES
|
||||
CONFIG_CRYPTO_CCM
|
||||
CONFIG_CRYPTO_AEAD
|
||||
CONFIG_CRYPTO_CMAC
|
||||
|
||||
|
||||
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.
|
||||
|
||||
--disable-a2dp
|
||||
|
||||
Disable A2DP profile
|
||||
|
||||
By default bluetoothd supports A2DP profile using a built-in
|
||||
plugin, this option disables it.
|
||||
|
||||
This option is provided for distributions that do not have any
|
||||
audio capabilities.
|
||||
|
||||
--disable-avrcp
|
||||
|
||||
Disable AVRCP profile
|
||||
|
||||
By default bluetoothd supports AVRCP profile using a built-in
|
||||
plugin, this option disables it.
|
||||
|
||||
This option is provided for distributions that do not have any
|
||||
audio capabilities.
|
||||
|
||||
--disable-network
|
||||
|
||||
Disable PANU, NAP, GN profiles
|
||||
|
||||
By default bluetoothd supports PANU, NAP and GN profile using a
|
||||
built-in plugin, this option disables it.
|
||||
|
||||
This option is provided for distributions that do not have any
|
||||
network capabilities.
|
||||
|
||||
--disable-hid
|
||||
|
||||
Disable HID profile
|
||||
|
||||
By default bluetoothd supports HID profile using a built-in
|
||||
plugin, this option disables it.
|
||||
|
||||
This option is provided for distributions that do not have any
|
||||
input capabilities.
|
||||
|
||||
--disable-hog
|
||||
|
||||
Disable HoG profile
|
||||
|
||||
By default bluetoothd supports HoG profile using a built-in
|
||||
plugin, this option disables it.
|
||||
|
||||
This option is provided for distributions that do not have any
|
||||
input capabilities.
|
||||
|
||||
--enable-testing
|
||||
|
||||
Enable testing tools
|
||||
|
||||
By default tools used only for testing emulation are disabled.
|
||||
This option can be used to enable them.
|
||||
|
||||
It is not recommended to enable this option for production
|
||||
systems. These tools may contain tests that depend on specific
|
||||
environment or kernel features in development.
|
||||
|
||||
--enable-experimental
|
||||
|
||||
Enable experimental tools
|
||||
|
||||
By default all tools 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 behavior of the experimental tools is unstable
|
||||
and might still change.
|
||||
|
||||
--enable-deprecated
|
||||
|
||||
Enable deprecated tools
|
||||
|
||||
By defauld all tools that are no longer maintained are
|
||||
disabled. This option can be used to enable them.
|
||||
|
||||
It is not recommended to enable this option for production
|
||||
systems. The behavior of the deprecated tools may be unstable
|
||||
or simply don't work anymore.
|
||||
|
||||
--enable-nfc
|
||||
|
||||
This option enable NFC pairing support.
|
||||
|
||||
By default the integration with neard is disabled, this gives
|
||||
the option to enable it in system where neard is supported.
|
||||
|
||||
The plugin is built into bluetoothd therefore it does not need
|
||||
to be package separately.
|
||||
|
||||
--enable-sap
|
||||
|
||||
This option enable SAP profile using sap plugin.
|
||||
|
||||
By default sap plugin is disabled since it requires tight
|
||||
integration with systems and is very rarely required.
|
||||
|
||||
The plugin is built into bluetoothd therefore it does not need
|
||||
to be package separately.
|
||||
|
||||
--enable-health
|
||||
|
||||
This option enable health profiles.
|
||||
|
||||
By default health plugin is disabled since its profiles are
|
||||
target for the health industry.
|
||||
|
||||
The plugin is built into bluetoothd therefore it does not need
|
||||
to be package separately.
|
||||
|
||||
--enable-midi
|
||||
|
||||
This option enable MIDI support via ALSA Sequencer.
|
||||
|
||||
By default midi plugin is disabled since it still considered
|
||||
experimental. When bluetoothd will create a new ALSA Sequencer
|
||||
client and port for each device connected that supports the
|
||||
MIDI GATT primary service.
|
||||
|
||||
The plugin is built into bluetoothd therefore it does not need
|
||||
to be package separately.
|
||||
|
||||
Information
|
||||
===========
|
||||
|
||||
Mailing lists:
|
||||
linux-bluetooth@vger.kernel.org
|
||||
|
||||
For additional information about the project visit BlueZ web site:
|
||||
http://www.bluez.org
|
||||
@@ -0,0 +1,224 @@
|
||||
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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
Management Interface
|
||||
====================
|
||||
|
||||
Mesh
|
||||
====
|
||||
- Add unit tests
|
||||
|
||||
Priority: High
|
||||
Complexity: C1
|
||||
|
||||
- Implement unified feature management mechanism for mesh nodes that are hosted
|
||||
on the same device
|
||||
|
||||
Priority: Medium
|
||||
Complexity: C2
|
||||
|
||||
- Implement mandatory Health Server model. Most likely, this will involve
|
||||
additions to mesh D-Bus API
|
||||
|
||||
Priority: Medium
|
||||
Complexity: C2
|
||||
|
||||
- Add support for GATT proxy server
|
||||
|
||||
Priority: Low
|
||||
Complexity: C4
|
||||
|
||||
- Merge common functionality from tools/mesh. Ideally, source code from the
|
||||
tools/mesh directory should completely dissapear.
|
||||
|
||||
Priority: Low
|
||||
Complexity: C2
|
||||
|
||||
- Support for Low Power Node (LPN)
|
||||
|
||||
Priority: Low
|
||||
Complexity: C4
|
||||
|
||||
@@ -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_32"
|
||||
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 -Wl,-z,now"
|
||||
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)
|
||||
])
|
||||
Vendored
+10499
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,857 @@
|
||||
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/shared/ad.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/shared/log.c \
|
||||
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)
|
||||
@@ -0,0 +1,322 @@
|
||||
if ANDROID
|
||||
|
||||
AM_CPPFLAGS += -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_CPPFLAGS = $(AM_CPPFLAGS) -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 \
|
||||
src/shared/log.h src/shared/log.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_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \
|
||||
-DPLUGINDIR=\""$(android_plugindir)"\"
|
||||
android_haltest_LDFLAGS = $(AM_LDFLAGS) -pthread
|
||||
android_haltest_LDADD = -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_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \
|
||||
-DPLUGINDIR=\""$(android_plugindir)"\"
|
||||
android_android_tester_LDADD = lib/libbluetooth-internal.la \
|
||||
src/libshared-glib.la $(GLIB_LIBS) -ldl
|
||||
android_android_tester_LDFLAGS = $(AM_LDFLAGS) -pthread
|
||||
|
||||
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_CPPFLAGS = $(AM_CPPFLAGS) -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_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \
|
||||
$(SBC_CFLAGS)
|
||||
android_audio_a2dp_default_la_LIBADD = $(SBC_LIBS) -lrt
|
||||
android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
|
||||
-no-undefined -pthread
|
||||
|
||||
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_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android
|
||||
android_audio_sco_default_la_LIBADD = $(SPEEXDSP_LIBS) -lrt
|
||||
android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
|
||||
-no-undefined
|
||||
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
|
||||
@@ -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.
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
bool bt_a2dp_sink_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
|
||||
void bt_a2dp_sink_unregister(void);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
|
||||
void bt_a2dp_unregister(void);
|
||||
@@ -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>
|
||||
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#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));
|
||||
@@ -0,0 +1,260 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
** Copyright 2011, The Android Open-Source Project
|
||||
**
|
||||
*/
|
||||
|
||||
//#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);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
** Copyright 2008, The Android Open-Source Project
|
||||
**
|
||||
*/
|
||||
|
||||
#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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2006-2010 Nokia Corporation
|
||||
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#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);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2006-2010 Nokia Corporation
|
||||
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,897 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,343 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Control PDU ids */
|
||||
#define AVRCP_GET_CAPABILITIES 0x10
|
||||
#define AVRCP_LIST_PLAYER_ATTRIBUTES 0X11
|
||||
#define AVRCP_LIST_PLAYER_VALUES 0x12
|
||||
#define AVRCP_GET_CURRENT_PLAYER_VALUE 0x13
|
||||
#define AVRCP_SET_PLAYER_VALUE 0x14
|
||||
#define AVRCP_GET_PLAYER_ATTRIBUTE_TEXT 0x15
|
||||
#define AVRCP_GET_PLAYER_VALUE_TEXT 0x16
|
||||
#define AVRCP_DISPLAYABLE_CHARSET 0x17
|
||||
#define AVRCP_CT_BATTERY_STATUS 0x18
|
||||
#define AVRCP_GET_ELEMENT_ATTRIBUTES 0x20
|
||||
#define AVRCP_GET_PLAY_STATUS 0x30
|
||||
#define AVRCP_REGISTER_NOTIFICATION 0x31
|
||||
#define AVRCP_REQUEST_CONTINUING 0x40
|
||||
#define AVRCP_ABORT_CONTINUING 0x41
|
||||
#define AVRCP_SET_ABSOLUTE_VOLUME 0x50
|
||||
#define AVRCP_SET_ADDRESSED_PLAYER 0x60
|
||||
#define AVRCP_SET_BROWSED_PLAYER 0x70
|
||||
#define AVRCP_GET_FOLDER_ITEMS 0x71
|
||||
#define AVRCP_CHANGE_PATH 0x72
|
||||
#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
|
||||
#define AVRCP_PLAY_ITEM 0x74
|
||||
#define AVRCP_SEARCH 0x80
|
||||
#define AVRCP_ADD_TO_NOW_PLAYING 0x90
|
||||
#define AVRCP_GENERAL_REJECT 0xA0
|
||||
|
||||
/* Notification events */
|
||||
#define AVRCP_EVENT_STATUS_CHANGED 0x01
|
||||
#define AVRCP_EVENT_TRACK_CHANGED 0x02
|
||||
#define AVRCP_EVENT_TRACK_REACHED_END 0x03
|
||||
#define AVRCP_EVENT_TRACK_REACHED_START 0x04
|
||||
#define AVRCP_EVENT_PLAYBACK_POS_CHANGED 0x05
|
||||
#define AVRCP_EVENT_SETTINGS_CHANGED 0x08
|
||||
#define AVRCP_EVENT_NOW_PLAYING_CONTENT_CHANGED 0x09
|
||||
#define AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED 0x0a
|
||||
#define AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED 0x0b
|
||||
#define AVRCP_EVENT_UIDS_CHANGED 0x0c
|
||||
#define AVRCP_EVENT_VOLUME_CHANGED 0x0d
|
||||
#define AVRCP_EVENT_LAST AVRCP_EVENT_VOLUME_CHANGED
|
||||
|
||||
/* Status codes */
|
||||
#define AVRCP_STATUS_INVALID_COMMAND 0x00
|
||||
#define AVRCP_STATUS_INVALID_PARAM 0x01
|
||||
#define AVRCP_STATUS_PARAM_NOT_FOUND 0x02
|
||||
#define AVRCP_STATUS_INTERNAL_ERROR 0x03
|
||||
#define AVRCP_STATUS_SUCCESS 0x04
|
||||
#define AVRCP_STATUS_UID_CHANGED 0x05
|
||||
#define AVRCP_STATUS_NOT_DIRECTORY 0x08
|
||||
#define AVRCP_STATUS_DOES_NOT_EXIST 0x09
|
||||
#define AVRCP_STATUS_INVALID_SCOPE 0x0a
|
||||
#define AVRCP_STATUS_OUT_OF_BOUNDS 0x0b
|
||||
#define AVRCP_STATUS_INVALID_PLAYER_ID 0x11
|
||||
#define AVRCP_STATUS_PLAYER_NOT_BROWSABLE 0x12
|
||||
#define AVRCP_STATUS_NO_AVAILABLE_PLAYERS 0x15
|
||||
#define AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED 0x16
|
||||
|
||||
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
|
||||
#define CAP_COMPANY_ID 0x02
|
||||
#define CAP_EVENTS_SUPPORTED 0x03
|
||||
|
||||
/* Player Attributes */
|
||||
#define AVRCP_ATTRIBUTE_ILEGAL 0x00
|
||||
#define AVRCP_ATTRIBUTE_EQUALIZER 0x01
|
||||
#define AVRCP_ATTRIBUTE_REPEAT_MODE 0x02
|
||||
#define AVRCP_ATTRIBUTE_SHUFFLE 0x03
|
||||
#define AVRCP_ATTRIBUTE_SCAN 0x04
|
||||
#define AVRCP_ATTRIBUTE_LAST AVRCP_ATTRIBUTE_SCAN
|
||||
|
||||
/* equalizer values */
|
||||
#define AVRCP_EQUALIZER_OFF 0x01
|
||||
#define AVRCP_EQUALIZER_ON 0x02
|
||||
|
||||
/* repeat mode values */
|
||||
#define AVRCP_REPEAT_MODE_OFF 0x01
|
||||
#define AVRCP_REPEAT_MODE_SINGLE 0x02
|
||||
#define AVRCP_REPEAT_MODE_ALL 0x03
|
||||
#define AVRCP_REPEAT_MODE_GROUP 0x04
|
||||
|
||||
/* shuffle values */
|
||||
#define AVRCP_SHUFFLE_OFF 0x01
|
||||
#define AVRCP_SHUFFLE_ALL 0x02
|
||||
#define AVRCP_SHUFFLE_GROUP 0x03
|
||||
|
||||
/* scan values */
|
||||
#define AVRCP_SCAN_OFF 0x01
|
||||
#define AVRCP_SCAN_ALL 0x02
|
||||
#define AVRCP_SCAN_GROUP 0x03
|
||||
|
||||
/* media attributes */
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_ILLEGAL 0x00
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_TITLE 0x01
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_ARTIST 0x02
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_ALBUM 0x03
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_TRACK 0x04
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_N_TRACKS 0x05
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_GENRE 0x06
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x07
|
||||
#define AVRCP_MEDIA_ATTRIBUTE_LAST AVRCP_MEDIA_ATTRIBUTE_DURATION
|
||||
|
||||
/* Media Scope */
|
||||
#define AVRCP_MEDIA_PLAYER_LIST 0x00
|
||||
#define AVRCP_MEDIA_PLAYER_VFS 0x01
|
||||
#define AVRCP_MEDIA_SEARCH 0x02
|
||||
#define AVRCP_MEDIA_NOW_PLAYING 0x03
|
||||
|
||||
/* SDP features */
|
||||
#define AVRCP_FEATURE_CATEGORY_1 0x0001
|
||||
#define AVRCP_FEATURE_CATEGORY_2 0x0002
|
||||
#define AVRCP_FEATURE_CATEGORY_3 0x0004
|
||||
#define AVRCP_FEATURE_CATEGORY_4 0x0008
|
||||
#define AVRCP_FEATURE_PLAYER_SETTINGS 0x0010
|
||||
#define AVRCP_FEATURE_GROUP_NAVIGATION 0x0020
|
||||
#define AVRCP_FEATURE_BROWSING 0x0040
|
||||
#define AVRCP_FEATURE_MULTIPLE_PLAYERS 0x0080
|
||||
|
||||
/* Company IDs for vendor dependent commands */
|
||||
#define IEEEID_BTSIG 0x001958
|
||||
|
||||
struct avrcp;
|
||||
|
||||
struct avrcp_control_ind {
|
||||
int (*get_capabilities) (struct avrcp *session, uint8_t transaction,
|
||||
void *user_data);
|
||||
int (*list_attributes) (struct avrcp *session, uint8_t transaction,
|
||||
void *user_data);
|
||||
int (*get_attribute_text) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
void *user_data);
|
||||
int (*list_values) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t attr, void *user_data);
|
||||
int (*get_value_text) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t attr, uint8_t number,
|
||||
uint8_t *values, void *user_data);
|
||||
int (*get_value) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
void *user_data);
|
||||
int (*set_value) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
uint8_t *values, void *user_data);
|
||||
int (*get_play_status) (struct avrcp *session, uint8_t transaction,
|
||||
void *user_data);
|
||||
int (*get_element_attributes) (struct avrcp *session,
|
||||
uint8_t transaction, uint64_t uid,
|
||||
uint8_t number, uint32_t *attrs,
|
||||
void *user_data);
|
||||
int (*register_notification) (struct avrcp *session,
|
||||
uint8_t transaction, uint8_t event,
|
||||
uint32_t interval, void *user_data);
|
||||
int (*set_volume) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t volume, void *user_data);
|
||||
int (*set_addressed) (struct avrcp *session, uint8_t transaction,
|
||||
uint16_t id, void *user_data);
|
||||
int (*set_browsed) (struct avrcp *session, uint8_t transaction,
|
||||
uint16_t id, void *user_data);
|
||||
int (*get_folder_items) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t scope, uint32_t start,
|
||||
uint32_t end, uint16_t number,
|
||||
uint32_t *attrs, void *user_data);
|
||||
int (*change_path) (struct avrcp *session, uint8_t transaction,
|
||||
uint16_t counter, uint8_t direction,
|
||||
uint64_t uid, void *user_data);
|
||||
int (*get_item_attributes) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t scope, uint64_t uid,
|
||||
uint16_t counter, uint8_t number,
|
||||
uint32_t *attrs, void *user_data);
|
||||
int (*play_item) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t scope, uint64_t uid,
|
||||
uint16_t counter, void *user_data);
|
||||
int (*search) (struct avrcp *session, uint8_t transaction,
|
||||
const char *string, void *user_data);
|
||||
int (*add_to_now_playing) (struct avrcp *session, uint8_t transaction,
|
||||
uint8_t scope, uint64_t uid,
|
||||
uint16_t counter, void *user_data);
|
||||
};
|
||||
|
||||
struct avrcp_control_cfm {
|
||||
void (*get_capabilities) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *params,
|
||||
void *user_data);
|
||||
void (*list_attributes) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
void *user_data);
|
||||
void (*get_attribute_text) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
char **text, void *user_data);
|
||||
void (*list_values) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *values,
|
||||
void *user_data);
|
||||
void (*get_value_text) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *values,
|
||||
char **text, void *user_data);
|
||||
void (*get_value) (struct avrcp *session, int err,
|
||||
uint8_t number, uint8_t *attrs,
|
||||
uint8_t *values, void *user_data);
|
||||
void (*set_value) (struct avrcp *session, int err, void *user_data);
|
||||
void (*get_play_status) (struct avrcp *session, int err,
|
||||
uint8_t status, uint32_t position,
|
||||
uint32_t duration, void *user_data);
|
||||
void (*get_element_attributes) (struct avrcp *session, int err,
|
||||
uint8_t number, uint32_t *attrs,
|
||||
char **text, void *user_data);
|
||||
bool (*register_notification) (struct avrcp *session, int err,
|
||||
uint8_t code, uint8_t event,
|
||||
void *params, void *user_data);
|
||||
void (*set_volume) (struct avrcp *session, int err, uint8_t volume,
|
||||
void *user_data);
|
||||
void (*set_addressed) (struct avrcp *session, int err,
|
||||
void *user_data);
|
||||
void (*set_browsed) (struct avrcp *session, int err,
|
||||
uint16_t counter, uint32_t items,
|
||||
char *path, void *user_data);
|
||||
void (*get_folder_items) (struct avrcp *session, int err,
|
||||
uint16_t counter, uint16_t number,
|
||||
uint8_t *params, void *user_data);
|
||||
void (*change_path) (struct avrcp *session, int err,
|
||||
uint32_t items, void *user_data);
|
||||
void (*get_item_attributes) (struct avrcp *session, int err,
|
||||
uint8_t number, uint32_t *attrs,
|
||||
char **text, void *user_data);
|
||||
void (*play_item) (struct avrcp *session, int err, void *user_data);
|
||||
void (*search) (struct avrcp *session, int err, uint16_t counter,
|
||||
uint32_t items, void *user_data);
|
||||
void (*add_to_now_playing) (struct avrcp *session, int err,
|
||||
void *user_data);
|
||||
};
|
||||
|
||||
struct avrcp_passthrough_handler {
|
||||
uint8_t op;
|
||||
bool (*func) (struct avrcp *session, bool pressed, void *user_data);
|
||||
};
|
||||
|
||||
typedef void (*avrcp_destroy_cb_t) (void *user_data);
|
||||
|
||||
struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
|
||||
void avrcp_shutdown(struct avrcp *session);
|
||||
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
|
||||
void *user_data);
|
||||
int avrcp_connect_browsing(struct avrcp *session, int fd, size_t imtu,
|
||||
size_t omtu);
|
||||
|
||||
void avrcp_register_player(struct avrcp *session,
|
||||
const struct avrcp_control_ind *ind,
|
||||
const struct avrcp_control_cfm *cfm,
|
||||
void *user_data);
|
||||
void avrcp_set_passthrough_handlers(struct avrcp *session,
|
||||
const struct avrcp_passthrough_handler *handlers,
|
||||
void *user_data);
|
||||
int avrcp_init_uinput(struct avrcp *session, const char *name,
|
||||
const char *address);
|
||||
int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
|
||||
uint8_t subunit, uint8_t pdu_id,
|
||||
const struct iovec *iov, int iov_cnt);
|
||||
int avrcp_get_capabilities(struct avrcp *session, uint8_t param);
|
||||
int avrcp_register_notification(struct avrcp *session, uint8_t event,
|
||||
uint32_t interval);
|
||||
int avrcp_list_player_attributes(struct avrcp *session);
|
||||
int avrcp_get_player_attribute_text(struct avrcp *session, uint8_t number,
|
||||
uint8_t *attrs);
|
||||
int avrcp_list_player_values(struct avrcp *session, uint8_t attr);
|
||||
int avrcp_get_player_value_text(struct avrcp *session, uint8_t attr,
|
||||
uint8_t number, uint8_t *values);
|
||||
int avrcp_set_player_value(struct avrcp *session, uint8_t number,
|
||||
uint8_t *attrs, uint8_t *values);
|
||||
int avrcp_get_current_player_value(struct avrcp *session, uint8_t number,
|
||||
uint8_t *attrs);
|
||||
int avrcp_get_play_status(struct avrcp *session);
|
||||
int avrcp_set_volume(struct avrcp *session, uint8_t volume);
|
||||
int avrcp_get_element_attributes(struct avrcp *session);
|
||||
int avrcp_set_addressed_player(struct avrcp *session, uint16_t player_id);
|
||||
int avrcp_set_browsed_player(struct avrcp *session, uint16_t player_id);
|
||||
int avrcp_get_folder_items(struct avrcp *session, uint8_t scope,
|
||||
uint32_t start, uint32_t end, uint8_t number,
|
||||
uint32_t *attrs);
|
||||
int avrcp_change_path(struct avrcp *session, uint8_t direction, uint64_t uid,
|
||||
uint16_t counter);
|
||||
int avrcp_get_item_attributes(struct avrcp *session, uint8_t scope,
|
||||
uint64_t uid, uint16_t counter, uint8_t number,
|
||||
uint32_t *attrs);
|
||||
int avrcp_play_item(struct avrcp *session, uint8_t scope, uint64_t uid,
|
||||
uint16_t counter);
|
||||
int avrcp_search(struct avrcp *session, const char *string);
|
||||
int avrcp_add_to_now_playing(struct avrcp *session, uint8_t scope, uint64_t uid,
|
||||
uint16_t counter);
|
||||
|
||||
int avrcp_get_capabilities_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *events);
|
||||
int avrcp_list_player_attributes_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *attrs);
|
||||
int avrcp_get_player_attribute_text_rsp(struct avrcp *session,
|
||||
uint8_t transaction, uint8_t number,
|
||||
uint8_t *attrs, const char **text);
|
||||
int avrcp_list_player_values_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t number, uint8_t *values);
|
||||
int avrcp_get_play_status_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint32_t position, uint32_t duration,
|
||||
uint8_t status);
|
||||
int avrcp_get_player_values_text_rsp(struct avrcp *session,
|
||||
uint8_t transaction, uint8_t number,
|
||||
uint8_t *values, const char **text);
|
||||
int avrcp_get_current_player_value_rsp(struct avrcp *session,
|
||||
uint8_t transaction, uint8_t number,
|
||||
uint8_t *attrs, uint8_t *values);
|
||||
int avrcp_set_player_value_rsp(struct avrcp *session, uint8_t transaction);
|
||||
int avrcp_get_element_attrs_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t *params, size_t params_len);
|
||||
int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t code, uint8_t event,
|
||||
void *data, size_t len);
|
||||
int avrcp_set_volume_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t volume);
|
||||
int avrcp_set_addressed_player_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status);
|
||||
int avrcp_set_browsed_player_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status, uint16_t counter,
|
||||
uint32_t items, uint8_t depth,
|
||||
const char **folders);
|
||||
int avrcp_get_folder_items_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status, uint16_t counter,
|
||||
uint8_t number, uint8_t *type,
|
||||
uint16_t *len, uint8_t **params);
|
||||
int avrcp_change_path_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status, uint32_t items);
|
||||
int avrcp_get_item_attributes_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status, uint8_t number,
|
||||
uint32_t *attrs, const char **text);
|
||||
int avrcp_play_item_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status);
|
||||
int avrcp_search_rsp(struct avrcp *session, uint8_t transaction, uint8_t status,
|
||||
uint16_t counter, uint32_t items);
|
||||
int avrcp_add_to_now_playing_rsp(struct avrcp *session, uint8_t transaction,
|
||||
uint8_t status);
|
||||
|
||||
int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
bool bt_avrcp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode);
|
||||
void bt_avrcp_unregister(void);
|
||||
|
||||
void bt_avrcp_connect(const bdaddr_t *dst);
|
||||
void bt_avrcp_disconnect(const bdaddr_t *dst);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
typedef void (*bt_bluetooth_ready)(int err, const bdaddr_t *addr);
|
||||
bool bt_bluetooth_start(int index, bool mgmt_dbg, bt_bluetooth_ready cb);
|
||||
|
||||
typedef void (*bt_bluetooth_stopped)(void);
|
||||
bool bt_bluetooth_stop(bt_bluetooth_stopped cb);
|
||||
|
||||
void bt_bluetooth_cleanup(void);
|
||||
|
||||
bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode);
|
||||
void bt_bluetooth_unregister(void);
|
||||
|
||||
int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint);
|
||||
void bt_adapter_remove_record(uint32_t handle);
|
||||
|
||||
typedef void (*bt_le_device_found)(const bdaddr_t *addr, int rssi,
|
||||
uint16_t eir_len, const void *eir,
|
||||
bool connectable, bool bonded);
|
||||
bool bt_le_register(bt_le_device_found cb);
|
||||
void bt_le_unregister(void);
|
||||
|
||||
bool bt_le_discovery_start(void);
|
||||
|
||||
typedef void (*bt_le_discovery_stopped)(void);
|
||||
bool bt_le_discovery_stop(bt_le_discovery_stopped cb);
|
||||
|
||||
typedef void (*bt_le_set_advertising_done)(uint8_t status, void *user_data);
|
||||
bool bt_le_set_advertising(bool advertising, bt_le_set_advertising_done cb,
|
||||
void *user_data);
|
||||
|
||||
uint8_t bt_get_device_android_type(const bdaddr_t *addr);
|
||||
bool bt_is_device_le(const bdaddr_t *addr);
|
||||
uint8_t bt_device_last_seen_bearer(const bdaddr_t *bdaddr);
|
||||
|
||||
const char *bt_get_adapter_name(void);
|
||||
bool bt_device_is_bonded(const bdaddr_t *bdaddr);
|
||||
bool bt_device_set_uuids(const bdaddr_t *bdaddr, GSList *uuids);
|
||||
|
||||
typedef void (*bt_read_device_rssi_done)(uint8_t status, const bdaddr_t *addr,
|
||||
int8_t rssi, void *user_data);
|
||||
bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
|
||||
void *user_data);
|
||||
|
||||
bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
|
||||
uint32_t *sign_cnt, bool *authenticated);
|
||||
|
||||
void bt_update_sign_counter(const bdaddr_t *addr, bool local, uint32_t val);
|
||||
|
||||
void bt_store_gatt_ccc(const bdaddr_t *addr, uint16_t value);
|
||||
|
||||
uint16_t bt_get_gatt_ccc(const bdaddr_t *addr);
|
||||
|
||||
const bdaddr_t *bt_get_id_addr(const bdaddr_t *addr, uint8_t *type);
|
||||
|
||||
bool bt_kernel_conn_control(void);
|
||||
|
||||
bool bt_auto_connect_add(const bdaddr_t *addr);
|
||||
|
||||
void bt_auto_connect_remove(const bdaddr_t *addr);
|
||||
|
||||
typedef void (*bt_unpaired_device_cb)(const bdaddr_t *addr);
|
||||
bool bt_unpaired_register(bt_unpaired_device_cb cb);
|
||||
void bt_unpaired_unregister(bt_unpaired_device_cb cb);
|
||||
|
||||
typedef void (*bt_paired_device_cb)(const bdaddr_t *addr);
|
||||
bool bt_paired_register(bt_paired_device_cb cb);
|
||||
void bt_paired_unregister(bt_paired_device_cb cb);
|
||||
bool bt_is_pairing(const bdaddr_t *addr);
|
||||
|
||||
struct bt_ad;
|
||||
struct adv_instance {
|
||||
uint8_t instance;
|
||||
int32_t timeout;
|
||||
int32_t type;
|
||||
struct bt_ad *ad;
|
||||
struct bt_ad *sr;
|
||||
unsigned include_tx_power:1;
|
||||
};
|
||||
|
||||
/* Values below have no C API definition - only in Java (AdvertiseManager.java)
|
||||
* and bluedroid
|
||||
*/
|
||||
enum android_adv_type {
|
||||
ANDROID_ADVERTISING_EVENT_TYPE_CONNECTABLE = 0,
|
||||
ANDROID_ADVERTISING_EVENT_TYPE_SCANNABLE = 2,
|
||||
ANDROID_ADVERTISING_EVENT_TYPE_NON_CONNECTABLE = 3,
|
||||
};
|
||||
|
||||
typedef void (*bt_le_addrm_advertising_done)(uint8_t status, void *user_data);
|
||||
bool bt_le_add_advertising(struct adv_instance *adv,
|
||||
bt_le_addrm_advertising_done cb, void *user_data);
|
||||
bool bt_le_remove_advertising(struct adv_instance *adv,
|
||||
bt_le_addrm_advertising_done cb, void *user_data);
|
||||
@@ -0,0 +1,242 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#if defined(ANDROID)
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "lib/hci.h"
|
||||
#include "lib/mgmt.h"
|
||||
|
||||
#include "src/shared/mainloop.h"
|
||||
#include "src/shared/btsnoop.h"
|
||||
#include "src/log.h"
|
||||
|
||||
#define DEFAULT_SNOOP_FILE "/sdcard/btsnoop_hci.log"
|
||||
|
||||
static struct btsnoop *snoop = NULL;
|
||||
static uint8_t monitor_buf[BTSNOOP_MAX_PACKET_SIZE];
|
||||
static int monitor_fd = -1;
|
||||
|
||||
static void signal_callback(int signum, void *user_data)
|
||||
{
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
mainloop_quit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_flags_from_opcode(uint16_t opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
case BTSNOOP_OPCODE_NEW_INDEX:
|
||||
case BTSNOOP_OPCODE_DEL_INDEX:
|
||||
break;
|
||||
case BTSNOOP_OPCODE_COMMAND_PKT:
|
||||
return 0x02;
|
||||
case BTSNOOP_OPCODE_EVENT_PKT:
|
||||
return 0x03;
|
||||
case BTSNOOP_OPCODE_ACL_TX_PKT:
|
||||
return 0x00;
|
||||
case BTSNOOP_OPCODE_ACL_RX_PKT:
|
||||
return 0x01;
|
||||
case BTSNOOP_OPCODE_SCO_TX_PKT:
|
||||
case BTSNOOP_OPCODE_SCO_RX_PKT:
|
||||
break;
|
||||
case BTSNOOP_OPCODE_OPEN_INDEX:
|
||||
case BTSNOOP_OPCODE_CLOSE_INDEX:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void data_callback(int fd, uint32_t events, void *user_data)
|
||||
{
|
||||
unsigned char control[32];
|
||||
struct mgmt_hdr hdr;
|
||||
struct msghdr msg;
|
||||
struct iovec iov[2];
|
||||
|
||||
if (events & (EPOLLERR | EPOLLHUP)) {
|
||||
mainloop_remove_fd(monitor_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
iov[0].iov_base = &hdr;
|
||||
iov[0].iov_len = MGMT_HDR_SIZE;
|
||||
iov[1].iov_base = monitor_buf;
|
||||
iov[1].iov_len = sizeof(monitor_buf);
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof(control);
|
||||
|
||||
while (true) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct timeval *tv = NULL;
|
||||
struct timeval ctv;
|
||||
uint16_t opcode, index, pktlen;
|
||||
uint32_t flags;
|
||||
ssize_t len;
|
||||
|
||||
len = recvmsg(monitor_fd, &msg, MSG_DONTWAIT);
|
||||
if (len < 0)
|
||||
break;
|
||||
|
||||
if (len < MGMT_HDR_SIZE)
|
||||
break;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||
continue;
|
||||
|
||||
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
|
||||
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
|
||||
tv = &ctv;
|
||||
}
|
||||
}
|
||||
|
||||
opcode = btohs(hdr.opcode);
|
||||
index = btohs(hdr.index);
|
||||
pktlen = btohs(hdr.len);
|
||||
|
||||
if (index)
|
||||
continue;
|
||||
|
||||
flags = get_flags_from_opcode(opcode);
|
||||
if (flags != 0xff)
|
||||
btsnoop_write(snoop, tv, flags, 0, monitor_buf, pktlen);
|
||||
}
|
||||
}
|
||||
|
||||
static int open_monitor(const char *path)
|
||||
{
|
||||
struct sockaddr_hci addr;
|
||||
int opt = 1;
|
||||
|
||||
snoop = btsnoop_create(path, 0, 0, BTSNOOP_FORMAT_HCI);
|
||||
if (!snoop)
|
||||
return -1;
|
||||
|
||||
monitor_fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
|
||||
if (monitor_fd < 0)
|
||||
goto failed;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = HCI_DEV_NONE;
|
||||
addr.hci_channel = HCI_CHANNEL_MONITOR;
|
||||
|
||||
if (bind(monitor_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||
goto failed_close;
|
||||
|
||||
if (setsockopt(monitor_fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))
|
||||
< 0)
|
||||
goto failed_close;
|
||||
|
||||
mainloop_add_fd(monitor_fd, EPOLLIN, data_callback, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_close:
|
||||
close(monitor_fd);
|
||||
monitor_fd = -1;
|
||||
|
||||
failed:
|
||||
btsnoop_unref(snoop);
|
||||
snoop = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void close_monitor(void)
|
||||
{
|
||||
btsnoop_unref(snoop);
|
||||
snoop = NULL;
|
||||
|
||||
close(monitor_fd);
|
||||
monitor_fd = -1;
|
||||
}
|
||||
|
||||
static void set_capabilities(void)
|
||||
{
|
||||
#if defined(ANDROID)
|
||||
struct __user_cap_header_struct header;
|
||||
struct __user_cap_data_struct cap;
|
||||
|
||||
header.version = _LINUX_CAPABILITY_VERSION;
|
||||
header.pid = 0;
|
||||
|
||||
/*
|
||||
* CAP_NET_RAW: for snooping
|
||||
* CAP_DAC_READ_SEARCH: override path search permissions
|
||||
*/
|
||||
cap.effective = cap.permitted =
|
||||
CAP_TO_MASK(CAP_NET_RAW) |
|
||||
CAP_TO_MASK(CAP_DAC_READ_SEARCH);
|
||||
cap.inheritable = 0;
|
||||
|
||||
/* TODO: Move to cap_set_proc once bionic support it */
|
||||
if (capset(&header, &cap) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *path;
|
||||
|
||||
__btd_log_init(NULL, 0);
|
||||
|
||||
DBG("");
|
||||
|
||||
set_capabilities();
|
||||
|
||||
if (argc > 1)
|
||||
path = argv[1];
|
||||
else
|
||||
path = DEFAULT_SNOOP_FILE;
|
||||
|
||||
mainloop_init();
|
||||
|
||||
if (!strcmp(DEFAULT_SNOOP_FILE, path))
|
||||
rename(DEFAULT_SNOOP_FILE, DEFAULT_SNOOP_FILE ".old");
|
||||
|
||||
if (open_monitor(path) < 0) {
|
||||
error("bluetoothd_snoop: start failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
info("bluetoothd_snoop: started");
|
||||
|
||||
mainloop_run_with_signal(signal_callback, NULL);
|
||||
|
||||
close_monitor();
|
||||
|
||||
info("bluetoothd_snoop: stopped");
|
||||
|
||||
__btd_log_cleanup();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include "hal-utils.h"
|
||||
|
||||
#define VALGRIND_BIN "/system/bin/valgrind"
|
||||
|
||||
#define BLUETOOTHD_BIN "/system/bin/bluetoothd-main"
|
||||
|
||||
static void run_valgrind(int debug, int mgmt_dbg)
|
||||
{
|
||||
char *prg_argv[7];
|
||||
char *prg_envp[3];
|
||||
|
||||
prg_argv[0] = VALGRIND_BIN;
|
||||
prg_argv[1] = "--leak-check=full";
|
||||
prg_argv[2] = "--track-origins=yes";
|
||||
prg_argv[3] = BLUETOOTHD_BIN;
|
||||
prg_argv[4] = debug ? "-d" : NULL;
|
||||
prg_argv[5] = mgmt_dbg ? "--mgmt-debug" : NULL;
|
||||
prg_argv[6] = NULL;
|
||||
|
||||
prg_envp[0] = "G_SLICE=always-malloc";
|
||||
prg_envp[1] = "G_DEBUG=gc-friendly";
|
||||
prg_envp[2] = NULL;
|
||||
|
||||
execve(prg_argv[0], prg_argv, prg_envp);
|
||||
}
|
||||
|
||||
static void run_bluetoothd(int debug, int mgmt_dbg)
|
||||
{
|
||||
char *prg_argv[4];
|
||||
char *prg_envp[1];
|
||||
|
||||
prg_argv[0] = BLUETOOTHD_BIN;
|
||||
prg_argv[1] = debug ? "-d" : NULL;
|
||||
prg_argv[2] = mgmt_dbg ? "--mgmt-debug" : NULL;
|
||||
prg_argv[3] = NULL;
|
||||
|
||||
prg_envp[0] = NULL;
|
||||
|
||||
execve(prg_argv[0], prg_argv, prg_envp);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
int debug = 0;
|
||||
int mgmt_dbg = 0;
|
||||
|
||||
if (get_config("debug", value, NULL) > 0 &&
|
||||
(!strcasecmp(value, "true") || atoi(value) > 0))
|
||||
debug = 1;
|
||||
|
||||
if (get_config("mgmtdbg", value, NULL) > 0 &&
|
||||
(!strcasecmp(value, "true") || atoi(value) > 0)) {
|
||||
debug = 1;
|
||||
mgmt_dbg = 1;
|
||||
}
|
||||
|
||||
if (get_config("valgrind", value, NULL) > 0 &&
|
||||
(!strcasecmp(value, "true") || atoi(value) > 0))
|
||||
run_valgrind(debug, mgmt_dbg);
|
||||
|
||||
/*
|
||||
* In case we failed to execute Valgrind, try to run bluetoothd
|
||||
* without it
|
||||
*/
|
||||
run_bluetoothd(debug, mgmt_dbg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
type bluetoothd, domain;
|
||||
type bluetoothd_exec, exec_type, file_type;
|
||||
type bluetoothd_main_exec, exec_type, file_type;
|
||||
|
||||
# Start bluetoothd from init
|
||||
init_daemon_domain(bluetoothd)
|
||||
|
||||
# Data file accesses
|
||||
allow bluetoothd bluetooth_data_file:dir w_dir_perms;
|
||||
allow bluetoothd bluetooth_data_file:notdevfile_class_set create_file_perms;
|
||||
|
||||
allow bluetoothd self:capability { setuid net_admin net_bind_service net_raw };
|
||||
allow bluetoothd kernel:system module_request;
|
||||
|
||||
# TODO: this may be romoved for userbuild where we don't use bluetoothd_wrapper
|
||||
allow bluetoothd bluetoothd_main_exec:file { execute execute_no_trans read open };
|
||||
|
||||
# IPC socket communication
|
||||
allow bluetoothd self:socket { create_socket_perms accept listen setopt getopt };
|
||||
|
||||
# Allow clients to use a socket provided by the bluetooth app.
|
||||
allow bluetoothd { bluetooth mediaserver }:unix_stream_socket connectto;
|
||||
|
||||
# Allow system app to use sockets and fds
|
||||
allow bluetooth bluetoothd:fd use;
|
||||
allow bluetooth bluetoothd:unix_stream_socket rw_socket_perms;
|
||||
|
||||
# Allow user bluetooth apps to use sockets and fds
|
||||
allow bluetoothdomain bluetoothd:fd use;
|
||||
allow bluetoothdomain bluetoothd:unix_stream_socket { getopt setopt getattr read write ioctl shutdown };
|
||||
|
||||
# Other domains that can create and use bluetooth sockets.
|
||||
allow bluetoothdomain self:socket create_socket_perms;
|
||||
|
||||
#This we might should put to mediaserver.te ?
|
||||
allow mediaserver bluetoothd:fd use;
|
||||
allow mediaserver bluetoothd:socket rw_socket_perms;
|
||||
|
||||
# needs /system/bin/log access
|
||||
allow bluetoothd devpts:chr_file rw_file_perms;
|
||||
|
||||
# access to uhid device
|
||||
allow bluetoothd uhid_device:chr_file rw_file_perms;
|
||||
|
||||
# tethering
|
||||
allow bluetoothd self:udp_socket create_socket_perms;
|
||||
allow bluetoothd self:tcp_socket { create ioctl };
|
||||
@@ -0,0 +1,17 @@
|
||||
type bluetoothd_snoop, domain;
|
||||
type bluetoothd_snoop_exec, exec_type, file_type;
|
||||
|
||||
# Start bluetoothd_snoop from init
|
||||
init_daemon_domain(bluetoothd_snoop)
|
||||
|
||||
# directory search and read caps
|
||||
allow bluetoothd_snoop self:capability dac_read_search;
|
||||
# use raw and packet sockets caps
|
||||
allow bluetoothd_snoop self:capability net_raw;
|
||||
|
||||
# monitor socket access
|
||||
allow bluetoothd_snoop self:socket { create bind setopt read };
|
||||
|
||||
# sdcard access
|
||||
allow bluetoothd_snoop fuse:dir w_dir_perms;
|
||||
allow bluetoothd_snoop fuse:file create_file_perms;
|
||||
@@ -0,0 +1,467 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "terminal.h"
|
||||
#include "pollhandler.h"
|
||||
#include "history.h"
|
||||
|
||||
static void process_line(char *line_buffer);
|
||||
|
||||
const struct interface *interfaces[] = {
|
||||
&audio_if,
|
||||
&sco_if,
|
||||
&bluetooth_if,
|
||||
&av_if,
|
||||
&rc_if,
|
||||
&gatt_if,
|
||||
&gatt_client_if,
|
||||
&gatt_server_if,
|
||||
&hf_if,
|
||||
&hh_if,
|
||||
&pan_if,
|
||||
&hl_if,
|
||||
&sock_if,
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
&hf_client_if,
|
||||
&mce_if,
|
||||
&ctrl_rc_if,
|
||||
&av_sink_if,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct method commands[];
|
||||
|
||||
struct method *get_method(struct method *methods, const char *name)
|
||||
{
|
||||
while (strcmp(methods->name, "") != 0) {
|
||||
if (strcmp(methods->name, name) == 0)
|
||||
return methods;
|
||||
methods++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* function returns interface of given name or NULL if not found */
|
||||
const struct interface *get_interface(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; interfaces[i] != NULL; ++i) {
|
||||
if (strcmp(interfaces[i]->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return interfaces[i];
|
||||
}
|
||||
|
||||
int haltest_error(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
va_start(args, format);
|
||||
ret = terminal_vprint(format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int haltest_info(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
va_start(args, format);
|
||||
ret = terminal_vprint(format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int haltest_warn(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
va_start(args, format);
|
||||
ret = terminal_vprint(format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void help_print_interface(const struct interface *i)
|
||||
{
|
||||
struct method *m;
|
||||
|
||||
for (m = i->methods; strcmp(m->name, "") != 0; m++)
|
||||
haltest_info("%s %s %s\n", i->name, m->name,
|
||||
(m->help ? m->help : ""));
|
||||
}
|
||||
|
||||
/* Help completion */
|
||||
static void help_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 2)
|
||||
*enum_func = interface_name;
|
||||
}
|
||||
|
||||
/* Help execution */
|
||||
static void help_p(int argc, const char **argv)
|
||||
{
|
||||
const struct method *m = commands;
|
||||
const struct interface **ip = interfaces;
|
||||
const struct interface *i;
|
||||
|
||||
if (argc == 1) {
|
||||
terminal_print("haltest allows to call Android HAL methods.\n");
|
||||
terminal_print("\nAvailable commands:\n");
|
||||
while (0 != strcmp(m->name, "")) {
|
||||
terminal_print("\t%s %s\n", m->name,
|
||||
(m->help ? m->help : ""));
|
||||
m++;
|
||||
}
|
||||
|
||||
terminal_print("\nAvailable interfaces to use:\n");
|
||||
while (NULL != *ip) {
|
||||
terminal_print("\t%s\n", (*ip)->name);
|
||||
ip++;
|
||||
}
|
||||
|
||||
terminal_print("\nTo get help on methods for each interface type:\n");
|
||||
terminal_print("\n\thelp <inerface>\n");
|
||||
terminal_print("\nBasic scenario:\n\tbluetooth init\n");
|
||||
terminal_print("\tbluetooth enable\n\tbluetooth start_discovery\n");
|
||||
terminal_print("\tbluetooth get_profile_interface handsfree\n");
|
||||
terminal_print("\thandsfree init\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
i = get_interface(argv[1]);
|
||||
if (i == NULL) {
|
||||
haltest_error("No such interface\n");
|
||||
return;
|
||||
}
|
||||
|
||||
help_print_interface(i);
|
||||
}
|
||||
|
||||
/* quit/exit execution */
|
||||
static void quit_p(int argc, const char **argv)
|
||||
{
|
||||
char cleanup_audio[] = "audio cleanup";
|
||||
|
||||
close_hw_bt_dev();
|
||||
process_line(cleanup_audio);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int fd_stack[10];
|
||||
static int fd_stack_pointer = 0;
|
||||
|
||||
static void stdin_handler(struct pollfd *pollfd);
|
||||
|
||||
static void process_file(const char *name)
|
||||
{
|
||||
int fd = open(name, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
haltest_error("Can't open file: %s for reading\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd_stack_pointer >= 10) {
|
||||
haltest_error("To many open files\n");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
fd_stack[fd_stack_pointer++] = fd;
|
||||
poll_unregister_fd(fd_stack[fd_stack_pointer - 2], stdin_handler);
|
||||
poll_register_fd(fd_stack[fd_stack_pointer - 1], POLLIN, stdin_handler);
|
||||
}
|
||||
|
||||
static void source_p(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
haltest_error("No file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
process_file(argv[1]);
|
||||
}
|
||||
|
||||
/* Commands available without interface */
|
||||
static struct method commands[] = {
|
||||
STD_METHODCH(help, "[<interface>]"),
|
||||
STD_METHOD(quit),
|
||||
METHOD("exit", quit_p, NULL, NULL),
|
||||
STD_METHODH(source, "<file>"),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
/* Gets comman by name */
|
||||
struct method *get_command(const char *name)
|
||||
{
|
||||
return get_method(commands, name);
|
||||
}
|
||||
|
||||
/* Function to enumerate interface names */
|
||||
const char *interface_name(void *v, int i)
|
||||
{
|
||||
return interfaces[i] ? interfaces[i]->name : NULL;
|
||||
}
|
||||
|
||||
/* Function to enumerate command and interface names */
|
||||
const char *command_name(void *v, int i)
|
||||
{
|
||||
int cmd_cnt = NELEM(commands);
|
||||
|
||||
if (i >= cmd_cnt)
|
||||
return interface_name(v, i - cmd_cnt);
|
||||
else
|
||||
return commands[i].name;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function changes input parameter line_buffer so it has
|
||||
* null termination after each token (due to strtok)
|
||||
* Output argv is filled with pointers to arguments
|
||||
* returns number of tokens parsed - argc
|
||||
*/
|
||||
static int command_line_to_argv(char *line_buffer, char *argv[], int argv_size)
|
||||
{
|
||||
static const char *token_breaks = "\r\n\t ";
|
||||
char *token;
|
||||
int argc = 0;
|
||||
|
||||
token = strtok(line_buffer, token_breaks);
|
||||
while (token != NULL && argc < (int) argv_size) {
|
||||
argv[argc++] = token;
|
||||
token = strtok(NULL, token_breaks);
|
||||
}
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
static void process_line(char *line_buffer)
|
||||
{
|
||||
char *argv[50];
|
||||
int argc;
|
||||
int i = 0;
|
||||
struct method *m;
|
||||
|
||||
argc = command_line_to_argv(line_buffer, argv, 50);
|
||||
if (argc < 1)
|
||||
return;
|
||||
|
||||
while (interfaces[i] != NULL) {
|
||||
if (strcmp(interfaces[i]->name, argv[0])) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argc < 2 || strcmp(argv[1], "?") == 0) {
|
||||
help_print_interface(interfaces[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
m = get_method(interfaces[i]->methods, argv[1]);
|
||||
if (m != NULL) {
|
||||
m->func(argc, (const char **) argv);
|
||||
return;
|
||||
}
|
||||
|
||||
haltest_error("No function %s found\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
/* No interface, try commands */
|
||||
m = get_command(argv[0]);
|
||||
if (m == NULL)
|
||||
haltest_error("No such command %s\n", argv[0]);
|
||||
else
|
||||
m->func(argc, (const char **) argv);
|
||||
}
|
||||
|
||||
/* called when there is something on stdin */
|
||||
static void stdin_handler(struct pollfd *pollfd)
|
||||
{
|
||||
char buf[10];
|
||||
|
||||
if (pollfd->revents & POLLIN) {
|
||||
int count = read(fd_stack[fd_stack_pointer - 1], buf, 10);
|
||||
|
||||
if (count > 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
terminal_process_char(buf[i], process_line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_stack_pointer > 1)
|
||||
poll_register_fd(fd_stack[fd_stack_pointer - 2], POLLIN,
|
||||
stdin_handler);
|
||||
if (fd_stack_pointer > 0) {
|
||||
poll_unregister_fd(fd_stack[--fd_stack_pointer], stdin_handler);
|
||||
|
||||
if (fd_stack[fd_stack_pointer])
|
||||
close(fd_stack[fd_stack_pointer]);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("haltest Android Bluetooth HAL testing tool\n"
|
||||
"Usage:\n");
|
||||
printf("\thaltest [options]\n");
|
||||
printf("options:\n"
|
||||
"\t-i --ivi Initialize only IVI interfaces\n"
|
||||
"\t-n, --no-init Don't initialize any interfaces\n"
|
||||
"\t-v --version Print version\n"
|
||||
"\t-h, --help Show help options\n");
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
printf("haltest version %s\n", VERSION);
|
||||
}
|
||||
|
||||
static const struct option main_options[] = {
|
||||
{ "no-init", no_argument, NULL, 'n' },
|
||||
{ "ivi", no_argument, NULL, 'i' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static bool no_init = false;
|
||||
static bool ivi_only = false;
|
||||
|
||||
static void parse_command_line(int argc, char *argv[])
|
||||
{
|
||||
for (;;) {
|
||||
int opt;
|
||||
|
||||
opt = getopt_long(argc, argv, "inhv", main_options, NULL);
|
||||
if (opt < 0)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
no_init = true;
|
||||
break;
|
||||
case 'i':
|
||||
ivi_only = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
case 'v':
|
||||
print_version();
|
||||
exit(0);
|
||||
default:
|
||||
putchar('\n');
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const interface_names[] = {
|
||||
BT_PROFILE_HANDSFREE_ID,
|
||||
BT_PROFILE_ADVANCED_AUDIO_ID,
|
||||
BT_PROFILE_AV_RC_ID,
|
||||
BT_PROFILE_HEALTH_ID,
|
||||
BT_PROFILE_HIDHOST_ID,
|
||||
BT_PROFILE_PAN_ID,
|
||||
BT_PROFILE_GATT_ID,
|
||||
BT_PROFILE_SOCKETS_ID,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const ivi_interface_inames[] = {
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
BT_PROFILE_HANDSFREE_CLIENT_ID,
|
||||
BT_PROFILE_MAP_CLIENT_ID,
|
||||
BT_PROFILE_AV_RC_CTRL_ID,
|
||||
BT_PROFILE_ADVANCED_AUDIO_SINK_ID,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static void init(const char * const *inames)
|
||||
{
|
||||
const struct method *m;
|
||||
const char *argv[4];
|
||||
char init_audio[] = "audio init";
|
||||
char init_sco[] = "sco init";
|
||||
char init_bt[] = "bluetooth init";
|
||||
uint32_t i;
|
||||
|
||||
process_line(init_audio);
|
||||
process_line(init_sco);
|
||||
process_line(init_bt);
|
||||
|
||||
m = get_interface_method("bluetooth", "get_profile_interface");
|
||||
|
||||
while (*inames) {
|
||||
argv[2] = *inames;
|
||||
m->func(3, argv);
|
||||
inames++;
|
||||
}
|
||||
|
||||
/* Init what is available to init */
|
||||
for (i = 3; i < NELEM(interfaces) - 1; ++i) {
|
||||
m = get_interface_method(interfaces[i]->name, "init");
|
||||
if (m != NULL)
|
||||
m->func(2, argv);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct stat rcstat;
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
terminal_setup();
|
||||
|
||||
if (!no_init) {
|
||||
if (ivi_only)
|
||||
init(ivi_interface_inames);
|
||||
else
|
||||
init(interface_names);
|
||||
}
|
||||
|
||||
history_restore(".haltest_history");
|
||||
|
||||
fd_stack[fd_stack_pointer++] = 0;
|
||||
/* Register command line handler */
|
||||
poll_register_fd(0, POLLIN, stdin_handler);
|
||||
|
||||
if (stat(".haltestrc", &rcstat) == 0 && (rcstat.st_mode & S_IFREG) != 0)
|
||||
process_file(".haltestrc");
|
||||
|
||||
poll_dispatch_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "history.h"
|
||||
|
||||
/* Very simple history storage for easy usage of tool */
|
||||
|
||||
#define HISTORY_DEPTH 40
|
||||
#define LINE_SIZE 200
|
||||
static char lines[HISTORY_DEPTH][LINE_SIZE];
|
||||
static int last_line = 0;
|
||||
static int history_size = 0;
|
||||
|
||||
/* TODO: Storing history not implemented yet */
|
||||
void history_store(const char *filename)
|
||||
{
|
||||
}
|
||||
|
||||
/* Restoring history from file */
|
||||
void history_restore(const char *filename)
|
||||
{
|
||||
char line[1000];
|
||||
FILE *f = fopen(filename, "rt");
|
||||
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
if (fgets(line, 1000, f) != NULL) {
|
||||
int l = strlen(line);
|
||||
|
||||
while (l > 0 && isspace(line[--l]))
|
||||
line[l] = 0;
|
||||
|
||||
if (l > 0)
|
||||
history_add_line(line);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* Add new line to history buffer */
|
||||
void history_add_line(const char *line)
|
||||
{
|
||||
if (line == NULL || strlen(line) == 0)
|
||||
return;
|
||||
|
||||
if (strcmp(line, lines[last_line]) == 0)
|
||||
return;
|
||||
|
||||
last_line = (last_line + 1) % HISTORY_DEPTH;
|
||||
strncpy(&lines[last_line][0], line, LINE_SIZE - 1);
|
||||
if (history_size < HISTORY_DEPTH)
|
||||
history_size++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get n-th line from history
|
||||
* 0 - means latest
|
||||
* -1 - means oldest
|
||||
* return -1 if there is no such line
|
||||
*/
|
||||
int history_get_line(int n, char *buf, int buf_size)
|
||||
{
|
||||
if (n == -1)
|
||||
n = history_size - 1;
|
||||
|
||||
if (n >= history_size || buf_size == 0 || n < 0)
|
||||
return -1;
|
||||
|
||||
strncpy(buf,
|
||||
&lines[(HISTORY_DEPTH + last_line - n) % HISTORY_DEPTH][0],
|
||||
buf_size - 1);
|
||||
buf[buf_size - 1] = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
void history_store(const char *filename);
|
||||
void history_restore(const char *filename);
|
||||
void history_add_line(const char *line);
|
||||
int history_get_line(int n, char *buf, int buf_size);
|
||||
@@ -0,0 +1,525 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
audio_hw_device_t *if_audio = NULL;
|
||||
static struct audio_stream_out *stream_out = NULL;
|
||||
|
||||
static size_t buffer_size = 0;
|
||||
static pthread_t play_thread = 0;
|
||||
static pthread_mutex_t outstream_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
enum state {
|
||||
STATE_STOPPED,
|
||||
STATE_STOPPING,
|
||||
STATE_PLAYING,
|
||||
STATE_SUSPENDED,
|
||||
STATE_MAX
|
||||
};
|
||||
|
||||
SINTMAP(audio_channel_mask_t, -1, "(AUDIO_CHANNEL_INVALID)")
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SIDE_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_MONO),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_STEREO),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD),
|
||||
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SURROUND),
|
||||
#else
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD_BACK),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD_SIDE),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_BACK),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
|
||||
#endif
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_7POINT1),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_ALL),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(audio_format_t, -1, "(AUDIO_FORMAT_INVALID)")
|
||||
DELEMENT(AUDIO_FORMAT_DEFAULT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM),
|
||||
DELEMENT(AUDIO_FORMAT_MP3),
|
||||
DELEMENT(AUDIO_FORMAT_AMR_NB),
|
||||
DELEMENT(AUDIO_FORMAT_AMR_WB),
|
||||
DELEMENT(AUDIO_FORMAT_AAC),
|
||||
DELEMENT(AUDIO_FORMAT_HE_AAC_V1),
|
||||
DELEMENT(AUDIO_FORMAT_HE_AAC_V2),
|
||||
DELEMENT(AUDIO_FORMAT_VORBIS),
|
||||
DELEMENT(AUDIO_FORMAT_MAIN_MASK),
|
||||
DELEMENT(AUDIO_FORMAT_SUB_MASK),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_16_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_8_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_32_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_8_24_BIT),
|
||||
ENDMAP
|
||||
|
||||
static int current_state = STATE_STOPPED;
|
||||
|
||||
#define SAMPLERATE 44100
|
||||
static short sample[SAMPLERATE];
|
||||
static uint16_t sample_pos;
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
const hw_module_t *module;
|
||||
audio_hw_device_t *device;
|
||||
|
||||
err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID,
|
||||
AUDIO_HARDWARE_MODULE_ID_A2DP, &module);
|
||||
if (err) {
|
||||
haltest_error("hw_get_module_by_class returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = audio_hw_device_open(module, &device);
|
||||
if (err) {
|
||||
haltest_error("audio_hw_device_open returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if_audio = device;
|
||||
}
|
||||
|
||||
static int feed_from_file(short *buffer, void *data)
|
||||
{
|
||||
FILE *in = data;
|
||||
return fread(buffer, buffer_size, 1, in);
|
||||
}
|
||||
|
||||
static int feed_from_generator(short *buffer, void *data)
|
||||
{
|
||||
size_t i = 0;
|
||||
float volume = 0.5;
|
||||
float *freq = data;
|
||||
float f = 1;
|
||||
|
||||
if (freq)
|
||||
f = *freq;
|
||||
|
||||
/* buffer_size is in bytes but we are using buffer of shorts (2 bytes)*/
|
||||
for (i = 0; i < buffer_size / sizeof(*buffer) - 1;) {
|
||||
if (sample_pos >= SAMPLERATE)
|
||||
sample_pos = sample_pos % SAMPLERATE;
|
||||
|
||||
/* Use the same sample for both channels */
|
||||
buffer[i++] = sample[sample_pos] * volume;
|
||||
buffer[i++] = sample[sample_pos] * volume;
|
||||
|
||||
sample_pos += f;
|
||||
}
|
||||
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
static void prepare_sample(void)
|
||||
{
|
||||
int x;
|
||||
double s;
|
||||
|
||||
haltest_info("Preparing audio sample...\n");
|
||||
|
||||
for (x = 0; x < SAMPLERATE; x++) {
|
||||
/* prepare sinusoidal 1Hz sample */
|
||||
s = (2.0 * 3.14159) * ((double)x / SAMPLERATE);
|
||||
s = sin(s);
|
||||
|
||||
/* remap <-1, 1> to signed 16bit PCM range */
|
||||
sample[x] = s * 32767;
|
||||
}
|
||||
|
||||
sample_pos = 0;
|
||||
}
|
||||
|
||||
static void *playback_thread(void *data)
|
||||
{
|
||||
int (*filbuff_cb) (short*, void*);
|
||||
short buffer[buffer_size / sizeof(short)];
|
||||
size_t len = 0;
|
||||
ssize_t w_len = 0;
|
||||
FILE *in = data;
|
||||
void *cb_data = NULL;
|
||||
float freq = 440.0;
|
||||
|
||||
/* Use file or fall back to generator */
|
||||
if (in) {
|
||||
filbuff_cb = feed_from_file;
|
||||
cb_data = in;
|
||||
} else {
|
||||
prepare_sample();
|
||||
filbuff_cb = feed_from_generator;
|
||||
cb_data = &freq;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_PLAYING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
do {
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
|
||||
if (current_state == STATE_STOPPING) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
break;
|
||||
} else if (current_state == STATE_SUSPENDED) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
usleep(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
len = filbuff_cb(buffer, cb_data);
|
||||
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
if (!stream_out) {
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
w_len = stream_out->write(stream_out, buffer, buffer_size);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
} while (len && w_len > 0);
|
||||
|
||||
if (in)
|
||||
fclose(in);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_STOPPED;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
haltest_info("Done playing.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void play_p(int argc, const char **argv)
|
||||
{
|
||||
const char *fname = NULL;
|
||||
FILE *in = NULL;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_error("Invalid audio file path.\n");
|
||||
haltest_info("Using sound generator.\n");
|
||||
} else {
|
||||
fname = argv[2];
|
||||
in = fopen(fname, "r");
|
||||
|
||||
if (in == NULL) {
|
||||
haltest_error("Cannot open file: %s\n", fname);
|
||||
return;
|
||||
}
|
||||
haltest_info("Playing file: %s\n", fname);
|
||||
}
|
||||
|
||||
if (buffer_size == 0) {
|
||||
haltest_error("Invalid buffer size. Was stream_out opened?\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
haltest_error("Already playing or stream suspended!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
goto fail;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
|
||||
haltest_error("Cannot create playback thread!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return;
|
||||
fail:
|
||||
if (in)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static void stop_p(int argc, const char **argv)
|
||||
{
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
current_state = STATE_STOPPING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
stream_out->common.standby(&stream_out->common);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
}
|
||||
|
||||
static void open_output_stream_p(int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_PLAYING) {
|
||||
haltest_error("Already playing!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
err = if_audio->open_output_stream(if_audio,
|
||||
0,
|
||||
AUDIO_DEVICE_OUT_ALL_A2DP,
|
||||
AUDIO_OUTPUT_FLAG_NONE,
|
||||
NULL,
|
||||
&stream_out, NULL);
|
||||
#else
|
||||
err = if_audio->open_output_stream(if_audio,
|
||||
0,
|
||||
AUDIO_DEVICE_OUT_ALL_A2DP,
|
||||
AUDIO_OUTPUT_FLAG_NONE,
|
||||
NULL,
|
||||
&stream_out);
|
||||
#endif
|
||||
if (err < 0) {
|
||||
haltest_error("open output stream returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
|
||||
if (buffer_size == 0)
|
||||
haltest_error("Invalid buffer size received!\n");
|
||||
else
|
||||
haltest_info("Using buffer size: %zu\n", buffer_size);
|
||||
}
|
||||
|
||||
static void close_output_stream_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
stop_p(argc, argv);
|
||||
|
||||
haltest_info("Waiting for playback thread...\n");
|
||||
pthread_join(play_thread, NULL);
|
||||
|
||||
if_audio->close_output_stream(if_audio, stream_out);
|
||||
|
||||
stream_out = NULL;
|
||||
buffer_size = 0;
|
||||
}
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
close_output_stream_p(0, NULL);
|
||||
} else {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
}
|
||||
|
||||
err = audio_hw_device_close(if_audio);
|
||||
if (err < 0) {
|
||||
haltest_error("audio_hw_device_close returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if_audio = NULL;
|
||||
}
|
||||
|
||||
static void suspend_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_PLAYING) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
current_state = STATE_SUSPENDED;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
stream_out->common.standby(&stream_out->common);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
}
|
||||
|
||||
static void resume_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_SUSPENDED)
|
||||
current_state = STATE_PLAYING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
}
|
||||
|
||||
static void get_latency_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Output audio stream latency: %d\n",
|
||||
stream_out->get_latency(stream_out));
|
||||
}
|
||||
|
||||
static void get_buffer_size_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Current output buffer size: %zu\n",
|
||||
stream_out->common.get_buffer_size(&stream_out->common));
|
||||
}
|
||||
|
||||
static void get_channels_p(int argc, const char **argv)
|
||||
{
|
||||
audio_channel_mask_t channels;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
channels = stream_out->common.get_channels(&stream_out->common);
|
||||
|
||||
haltest_info("Channels: %s\n", audio_channel_mask_t2str(channels));
|
||||
}
|
||||
|
||||
static void get_format_p(int argc, const char **argv)
|
||||
{
|
||||
audio_format_t format;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
format = stream_out->common.get_format(&stream_out->common);
|
||||
|
||||
haltest_info("Format: %s\n", audio_format_t2str(format));
|
||||
}
|
||||
|
||||
static void get_sample_rate_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Current sample rate: %d\n",
|
||||
stream_out->common.get_sample_rate(&stream_out->common));
|
||||
}
|
||||
|
||||
static void get_parameters_p(int argc, const char **argv)
|
||||
{
|
||||
const char *keystr;
|
||||
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_info("No keys given.\n");
|
||||
keystr = "";
|
||||
} else {
|
||||
keystr = argv[2];
|
||||
}
|
||||
|
||||
haltest_info("Current parameters: %s\n",
|
||||
stream_out->common.get_parameters(&stream_out->common,
|
||||
keystr));
|
||||
}
|
||||
|
||||
static void set_parameters_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_error("No key=value; pairs given.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
stream_out->common.set_parameters(&stream_out->common, argv[2]);
|
||||
}
|
||||
|
||||
static void set_sample_rate_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3)
|
||||
return;
|
||||
|
||||
stream_out->common.set_sample_rate(&stream_out->common, atoi(argv[2]));
|
||||
}
|
||||
|
||||
static void init_check_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio);
|
||||
|
||||
haltest_info("Init check result: %d\n", if_audio->init_check(if_audio));
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHOD(cleanup),
|
||||
STD_METHOD(open_output_stream),
|
||||
STD_METHOD(close_output_stream),
|
||||
STD_METHODH(play, "<path to pcm file>"),
|
||||
STD_METHOD(stop),
|
||||
STD_METHOD(suspend),
|
||||
STD_METHOD(resume),
|
||||
STD_METHOD(get_latency),
|
||||
STD_METHOD(get_buffer_size),
|
||||
STD_METHOD(get_channels),
|
||||
STD_METHOD(get_format),
|
||||
STD_METHOD(get_sample_rate),
|
||||
STD_METHODH(get_parameters, "<A2dpSuspended;closing>"),
|
||||
STD_METHODH(set_parameters, "<A2dpSuspended=value;closing=value>"),
|
||||
STD_METHODH(set_sample_rate, "<sample rate>"),
|
||||
STD_METHOD(init_check),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface audio_if = {
|
||||
.name = "audio",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btav_interface_t *if_av_sink = NULL;
|
||||
|
||||
SINTMAP(btav_connection_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTED),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_CONNECTING),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_CONNECTED),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btav_audio_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTAV_AUDIO_STATE_REMOTE_SUSPEND),
|
||||
DELEMENT(BTAV_AUDIO_STATE_STOPPED),
|
||||
DELEMENT(BTAV_AUDIO_STATE_STARTED),
|
||||
ENDMAP
|
||||
|
||||
static char last_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
static void connection_state(btav_connection_state_t state,
|
||||
bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("(sink) %s: connection_state=%s remote_bd_addr=%s\n",
|
||||
__func__, btav_connection_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
static void audio_state(btav_audio_state_t state, bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("(sink) %s: audio_state=%s remote_bd_addr=%s\n", __func__,
|
||||
btav_audio_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
static void audio_config(bt_bdaddr_t *bd_addr, uint32_t sample_rate,
|
||||
uint8_t channel_count) {
|
||||
haltest_info("(sink) %s: addr=%s\n sample_rate=%d\n channel_count=%d\n",
|
||||
__func__, bt_bdaddr_t2str(bd_addr, last_addr),
|
||||
sample_rate, channel_count);
|
||||
}
|
||||
|
||||
static btav_callbacks_t av_cbacks = {
|
||||
.size = sizeof(av_cbacks),
|
||||
.connection_state_cb = connection_state,
|
||||
.audio_state_cb = audio_state,
|
||||
.audio_config_cb = audio_config,
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_av_sink);
|
||||
|
||||
EXEC(if_av_sink->init, &av_cbacks);
|
||||
}
|
||||
|
||||
/* connect */
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_av_sink);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_av_sink->connect, &addr);
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
|
||||
static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = last_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_av_sink);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_av_sink->disconnect, &addr);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_av_sink);
|
||||
|
||||
EXECV(if_av_sink->cleanup);
|
||||
if_av_sink = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(connect, "<addr>"),
|
||||
STD_METHODCH(disconnect, "<addr>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface av_sink_if = {
|
||||
.name = "av-sink",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btav_interface_t *if_av = NULL;
|
||||
|
||||
SINTMAP(btav_connection_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTED),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_CONNECTING),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_CONNECTED),
|
||||
DELEMENT(BTAV_CONNECTION_STATE_DISCONNECTING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btav_audio_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTAV_AUDIO_STATE_REMOTE_SUSPEND),
|
||||
DELEMENT(BTAV_AUDIO_STATE_STOPPED),
|
||||
DELEMENT(BTAV_AUDIO_STATE_STARTED),
|
||||
ENDMAP
|
||||
|
||||
static char last_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
static void connection_state(btav_connection_state_t state,
|
||||
bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("%s: connection_state=%s remote_bd_addr=%s\n", __func__,
|
||||
btav_connection_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
static void audio_state(btav_audio_state_t state, bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("%s: audio_state=%s remote_bd_addr=%s\n", __func__,
|
||||
btav_audio_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
static void audio_config(bt_bdaddr_t *bd_addr, uint32_t sample_rate,
|
||||
uint8_t channel_count) {
|
||||
haltest_info("%s: remote_addr=%s\n sample_rate=%d\n channel_count=%d\n",
|
||||
__func__, bt_bdaddr_t2str(bd_addr, last_addr),
|
||||
sample_rate, channel_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
static btav_callbacks_t av_cbacks = {
|
||||
.size = sizeof(av_cbacks),
|
||||
.connection_state_cb = connection_state,
|
||||
.audio_state_cb = audio_state,
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
.audio_config_cb = audio_config,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_av);
|
||||
|
||||
EXEC(if_av->init, &av_cbacks);
|
||||
}
|
||||
|
||||
/* connect */
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_av);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_av->connect, &addr);
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
|
||||
static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = last_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_av);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_av->disconnect, &addr);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_av);
|
||||
|
||||
EXECV(if_av->cleanup);
|
||||
if_av = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(connect, "<addr>"),
|
||||
STD_METHODCH(disconnect, "<addr>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface av_if = {
|
||||
.name = "av",
|
||||
.methods = methods
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,658 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const bthf_client_interface_t *if_hf_client = NULL;
|
||||
|
||||
static char last_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
SINTMAP(bthf_client_connection_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED),
|
||||
DELEMENT(BTHF_CLIENT_CONNECTION_STATE_CONNECTING),
|
||||
DELEMENT(BTHF_CLIENT_CONNECTION_STATE_CONNECTED),
|
||||
DELEMENT(BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED),
|
||||
DELEMENT(BTHF_CLIENT_CONNECTION_STATE_DISCONNECTING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_audio_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_AUDIO_STATE_DISCONNECTED),
|
||||
DELEMENT(BTHF_CLIENT_AUDIO_STATE_CONNECTING),
|
||||
DELEMENT(BTHF_CLIENT_AUDIO_STATE_CONNECTED),
|
||||
DELEMENT(BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_vr_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_VR_STATE_STOPPED),
|
||||
DELEMENT(BTHF_CLIENT_VR_STATE_STARTED),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_network_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_NETWORK_STATE_NOT_AVAILABLE),
|
||||
DELEMENT(BTHF_CLIENT_NETWORK_STATE_AVAILABLE),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_service_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_SERVICE_TYPE_HOME),
|
||||
DELEMENT(BTHF_CLIENT_SERVICE_TYPE_ROAMING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_call_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALL_NO_CALLS_IN_PROGRESS),
|
||||
DELEMENT(BTHF_CLIENT_CALL_CALLS_IN_PROGRESS),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_callsetup_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALLSETUP_NONE),
|
||||
DELEMENT(BTHF_CLIENT_CALLSETUP_INCOMING),
|
||||
DELEMENT(BTHF_CLIENT_CALLSETUP_OUTGOING),
|
||||
DELEMENT(BTHF_CLIENT_CALLSETUP_ALERTING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_callheld_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALLHELD_NONE),
|
||||
DELEMENT(BTHF_CLIENT_CALLHELD_HOLD_AND_ACTIVE),
|
||||
DELEMENT(BTHF_CLIENT_CALLHELD_HOLD),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_resp_and_hold_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_RESP_AND_HOLD_HELD),
|
||||
DELEMENT(BTRH_CLIENT_RESP_AND_HOLD_ACCEPT),
|
||||
DELEMENT(BTRH_CLIENT_RESP_AND_HOLD_REJECT),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_call_direction_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALL_DIRECTION_OUTGOING),
|
||||
DELEMENT(BTHF_CLIENT_CALL_DIRECTION_INCOMING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_call_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_ACTIVE),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_HELD),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_DIALING),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_ALERTING),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_INCOMING),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_WAITING),
|
||||
DELEMENT(BTHF_CLIENT_CALL_STATE_HELD_BY_RESP_HOLD),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_call_mpty_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE),
|
||||
DELEMENT(BTHF_CLIENT_CALL_MPTY_TYPE_MULTI),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_volume_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_VOLUME_TYPE_SPK),
|
||||
DELEMENT(BTHF_CLIENT_VOLUME_TYPE_MIC),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_cmd_complete_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_OK),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_CARRIER),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_BUSY),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_NO_ANSWER),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_DELAYED),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_BLACKLISTED),
|
||||
DELEMENT(BTHF_CLIENT_CMD_COMPLETE_ERROR_CME),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_subscriber_service_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_SERVICE_UNKNOWN),
|
||||
DELEMENT(BTHF_CLIENT_SERVICE_VOICE),
|
||||
DELEMENT(BTHF_CLIENT_SERVICE_FAX),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_in_band_ring_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED),
|
||||
DELEMENT(BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthf_client_call_action_t, -1, "(unknown)")
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_0),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_1),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_2),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_3),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_4),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_1x),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHLD_2x),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_ATA),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_CHUP),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_BTRH_0),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_BTRH_1),
|
||||
DELEMENT(BTHF_CLIENT_CALL_ACTION_BTRH_2),
|
||||
ENDMAP
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
static char features_str[512];
|
||||
|
||||
static const char *pear_features_t2str(int feat)
|
||||
{
|
||||
memset(features_str, 0, sizeof(features_str));
|
||||
|
||||
sprintf(features_str, "BTHF_CLIENT_PEER_FEAT_3WAY: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_ECNR: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_VREC: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_INBAND: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_VTAG: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_REJECT: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_ECS: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_ECC: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_EXTERR: %s,\n"
|
||||
"BTHF_CLIENT_PEER_FEAT_CODEC: %s,\n",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_3WAY ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_ECNR ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_VREC ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_INBAND ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_VTAG ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_REJECT ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_ECS ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_ECC ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_EXTERR ? "True" : "False",
|
||||
feat & BTHF_CLIENT_PEER_FEAT_CODEC ? "True" : "False");
|
||||
|
||||
return features_str;
|
||||
}
|
||||
|
||||
static const char *chld_features_t2str(int feat)
|
||||
{
|
||||
memset(features_str, 0, sizeof(features_str));
|
||||
|
||||
sprintf(features_str,
|
||||
"BTHF_CLIENT_CHLD_FEAT_REL: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_REL_ACC: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_REL_X: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_HOLD_ACC: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_PRIV_X: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_MERGE: %s,\n"
|
||||
"BTHF_CLIENT_CHLD_FEAT_MERGE_DETACH: %s,\n",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_REL ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_REL_ACC ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_REL_X ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_HOLD_ACC ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_PRIV_X ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_MERGE ? "True" : "False",
|
||||
feat & BTHF_CLIENT_CHLD_FEAT_MERGE_DETACH ? "True" : "False");
|
||||
|
||||
return features_str;
|
||||
}
|
||||
|
||||
/* Callback for connection state change. */
|
||||
static void hf_client_connection_state_callback(
|
||||
bthf_client_connection_state_t state,
|
||||
unsigned int peer_feat,
|
||||
unsigned int chld_feat,
|
||||
bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("%s: state=%s bd_addr=%s\n", __func__,
|
||||
bthf_client_connection_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
|
||||
if (state != BTHF_CLIENT_CONNECTION_STATE_CONNECTED)
|
||||
return;
|
||||
|
||||
haltest_info("\tpeer_features%s\n", pear_features_t2str(peer_feat));
|
||||
haltest_info("\tchld_feat=%s\n", chld_features_t2str(chld_feat));
|
||||
}
|
||||
|
||||
/* Callback for audio connection state change. */
|
||||
static void hf_client_audio_state_callback(bthf_client_audio_state_t state,
|
||||
bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("%s: state=%s bd_addr=%s\n", __func__,
|
||||
bthf_client_audio_state_t2str(state),
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
/* Callback for VR connection state change. */
|
||||
static void hf_client_vr_cmd_callback(bthf_client_vr_state_t state)
|
||||
{
|
||||
haltest_info("%s: vr_state=%s\n", __func__,
|
||||
bthf_client_vr_state_t2str(state));
|
||||
}
|
||||
|
||||
/* Callback for network state change */
|
||||
static void hf_client_network_state_callback(bthf_client_network_state_t state)
|
||||
{
|
||||
haltest_info("%s: network_state=%s\n", __func__,
|
||||
bthf_client_network_state_t2str(state));
|
||||
}
|
||||
|
||||
/* Callback for network roaming status change */
|
||||
static void hf_client_network_roaming_callback(bthf_client_service_type_t type)
|
||||
{
|
||||
haltest_info("%s: service_type=%s\n", __func__,
|
||||
bthf_client_service_type_t2str(type));
|
||||
}
|
||||
|
||||
/* Callback for signal strength indication */
|
||||
static void hf_client_network_signal_callback(int signal_strength)
|
||||
{
|
||||
haltest_info("%s: signal strength=%d\n", __func__, signal_strength);
|
||||
}
|
||||
|
||||
/* Callback for battery level indication */
|
||||
static void hf_client_battery_level_callback(int battery_level)
|
||||
{
|
||||
haltest_info("%s: battery_lvl=%d\n", __func__, battery_level);
|
||||
}
|
||||
|
||||
/* Callback for current operator name */
|
||||
static void hf_client_current_operator_callback(const char *name)
|
||||
{
|
||||
haltest_info("%s: operator_name=%s\n", __func__, name);
|
||||
}
|
||||
|
||||
/* Callback for call indicator */
|
||||
static void hf_client_call_callback(bthf_client_call_t call)
|
||||
{
|
||||
haltest_info("%s: call_state=%s\n", __func__,
|
||||
bthf_client_call_t2str(call));
|
||||
}
|
||||
|
||||
/* Callback for callsetup indicator */
|
||||
static void hf_client_callsetup_callback(bthf_client_callsetup_t callsetup)
|
||||
{
|
||||
haltest_info("%s: callsetup=%s\n", __func__,
|
||||
bthf_client_callsetup_t2str(callsetup));
|
||||
}
|
||||
|
||||
/* Callback for callheld indicator */
|
||||
static void hf_client_callheld_callback(bthf_client_callheld_t callheld)
|
||||
{
|
||||
haltest_info("%s: callheld=%s\n", __func__,
|
||||
bthf_client_callheld_t2str(callheld));
|
||||
}
|
||||
|
||||
/* Callback for response and hold */
|
||||
static void hf_client_resp_and_hold_callback(
|
||||
bthf_client_resp_and_hold_t resp_and_hold)
|
||||
{
|
||||
haltest_info("%s: resp_and_hold=%s\n", __func__,
|
||||
bthf_client_resp_and_hold_t2str(resp_and_hold));
|
||||
}
|
||||
|
||||
/* Callback for Calling Line Identification notification */
|
||||
static void hf_client_clip_callback(const char *number)
|
||||
{
|
||||
haltest_info("%s: number=%s\n", __func__, number);
|
||||
}
|
||||
|
||||
/* Callback for Call Waiting notification */
|
||||
static void hf_client_call_waiting_callback(const char *number)
|
||||
{
|
||||
haltest_info("%s: number=%s\n", __func__, number);
|
||||
}
|
||||
|
||||
/* Callback for listing current calls. Can be called multiple time. */
|
||||
static void hf_client_current_calls_callback(int index,
|
||||
bthf_client_call_direction_t dir,
|
||||
bthf_client_call_state_t state,
|
||||
bthf_client_call_mpty_type_t mpty,
|
||||
const char *number)
|
||||
{
|
||||
haltest_info("%s: index=%d, direction=%s, state=%s, m_party=%s\n",
|
||||
__func__, index,
|
||||
bthf_client_call_direction_t2str(dir),
|
||||
bthf_client_call_state_t2str(state),
|
||||
bthf_client_call_mpty_type_t2str(mpty));
|
||||
|
||||
if (number)
|
||||
haltest_info("%s: number=%s\n", __func__, number);
|
||||
}
|
||||
|
||||
/* Callback for audio volume change */
|
||||
static void hf_client_volume_change_callback(bthf_client_volume_type_t type,
|
||||
int volume)
|
||||
{
|
||||
haltest_info("%s: vol_type=%s, value=%d\n", __func__,
|
||||
bthf_client_volume_type_t2str(type), volume);
|
||||
}
|
||||
|
||||
/* Callback for command complete event */
|
||||
static void hf_client_cmd_complete_callback(bthf_client_cmd_complete_t type,
|
||||
int cme)
|
||||
{
|
||||
haltest_info("%s: type=%s, cme=%d\n", __func__,
|
||||
bthf_client_cmd_complete_t2str(type), cme);
|
||||
}
|
||||
|
||||
/* Callback for subscriber information */
|
||||
static void hf_client_subscriber_info_callback(const char *name,
|
||||
bthf_client_subscriber_service_type_t type)
|
||||
{
|
||||
haltest_info("%s: name=%s, type=%s\n", __func__, name,
|
||||
bthf_client_subscriber_service_type_t2str(type));
|
||||
}
|
||||
|
||||
/* Callback for in-band ring tone settings */
|
||||
static void hf_client_in_band_ring_tone_callback(
|
||||
bthf_client_in_band_ring_state_t state)
|
||||
{
|
||||
haltest_info("%s: state=%s\n", __func__,
|
||||
bthf_client_in_band_ring_state_t2str(state));
|
||||
}
|
||||
|
||||
/* Callback for requested number from AG */
|
||||
static void hf_client_last_voice_tag_number_callback(const char *number)
|
||||
{
|
||||
haltest_info("%s: number=%s\n", __func__, number);
|
||||
}
|
||||
|
||||
/* Callback for sending ring indication to app */
|
||||
static void hf_client_ring_indication_callback(void)
|
||||
{
|
||||
haltest_info("%s\n", __func__);
|
||||
}
|
||||
|
||||
static bthf_client_callbacks_t hf_client_cbacks = {
|
||||
.size = sizeof(hf_client_cbacks),
|
||||
.connection_state_cb = hf_client_connection_state_callback,
|
||||
.audio_state_cb = hf_client_audio_state_callback,
|
||||
.vr_cmd_cb = hf_client_vr_cmd_callback,
|
||||
.network_state_cb = hf_client_network_state_callback,
|
||||
.network_roaming_cb = hf_client_network_roaming_callback,
|
||||
.network_signal_cb = hf_client_network_signal_callback,
|
||||
.battery_level_cb = hf_client_battery_level_callback,
|
||||
.current_operator_cb = hf_client_current_operator_callback,
|
||||
.call_cb = hf_client_call_callback,
|
||||
.callsetup_cb = hf_client_callsetup_callback,
|
||||
.callheld_cb = hf_client_callheld_callback,
|
||||
.resp_and_hold_cb = hf_client_resp_and_hold_callback,
|
||||
.clip_cb = hf_client_clip_callback,
|
||||
.call_waiting_cb = hf_client_call_waiting_callback,
|
||||
.current_calls_cb = hf_client_current_calls_callback,
|
||||
.volume_change_cb = hf_client_volume_change_callback,
|
||||
.cmd_complete_cb = hf_client_cmd_complete_callback,
|
||||
.subscriber_info_cb = hf_client_subscriber_info_callback,
|
||||
.in_band_ring_tone_cb = hf_client_in_band_ring_tone_callback,
|
||||
.last_voice_tag_number_callback =
|
||||
hf_client_last_voice_tag_number_callback,
|
||||
.ring_indication_cb = hf_client_ring_indication_callback,
|
||||
};
|
||||
|
||||
/* init */
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->init, &hf_client_cbacks);
|
||||
}
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
/* connect to audio gateway */
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hf_client->connect, &addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This completion function will be used for several methods
|
||||
* returning recently connected address
|
||||
*/
|
||||
static void connected_addr_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = last_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map completion to connected_addr_c */
|
||||
#define disconnect_c connected_addr_c
|
||||
|
||||
/* disconnect from audio gateway */
|
||||
static void disconnect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hf_client->disconnect, &addr);
|
||||
}
|
||||
|
||||
static void connect_audio_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
/* create an audio connection */
|
||||
static void connect_audio_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hf_client->connect_audio, &addr);
|
||||
}
|
||||
|
||||
/* Map completion to connected_addr_c */
|
||||
#define disconnect_audio_c connected_addr_c
|
||||
|
||||
/* close the audio connection */
|
||||
static void disconnect_audio_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hf_client->disconnect_audio, &addr);
|
||||
}
|
||||
|
||||
/* start voice recognition */
|
||||
static void start_voice_recognition_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->start_voice_recognition);
|
||||
}
|
||||
|
||||
/* stop voice recognition */
|
||||
static void stop_voice_recognition_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->stop_voice_recognition);
|
||||
}
|
||||
|
||||
static void volume_control_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(bthf_client_volume_type_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
/* volume control */
|
||||
static void volume_control_p(int argc, const char **argv)
|
||||
{
|
||||
bthf_client_volume_type_t type;
|
||||
int volume;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
/* volume type */
|
||||
if (argc <= 2) {
|
||||
haltest_error("No volume type specified\n");
|
||||
return;
|
||||
}
|
||||
type = str2bthf_client_volume_type_t(argv[2]);
|
||||
|
||||
/* volume */
|
||||
if (argc <= 3) {
|
||||
haltest_error("No volume specified\n");
|
||||
return;
|
||||
}
|
||||
volume = atoi(argv[3]);
|
||||
|
||||
EXEC(if_hf_client->volume_control, type, volume);
|
||||
}
|
||||
|
||||
/* place a call with number a number */
|
||||
static void dial_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
/* number string */
|
||||
if (argc <= 2) {
|
||||
haltest_info("Number not specified. Redial\n");
|
||||
EXEC(if_hf_client->dial, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
EXEC(if_hf_client->dial, argv[2]);
|
||||
}
|
||||
|
||||
/* place a call with number specified by location (speed dial) */
|
||||
static void dial_memory_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
/* memory index */
|
||||
if (argc <= 2) {
|
||||
haltest_error("No memory index specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EXEC(if_hf_client->dial_memory, atoi(argv[2]));
|
||||
}
|
||||
|
||||
static void handle_call_action_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(bthf_client_call_action_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform specified call related action */
|
||||
static void handle_call_action_p(int argc, const char **argv)
|
||||
{
|
||||
bthf_client_call_action_t action;
|
||||
int index = 0;
|
||||
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
/* action */
|
||||
if (argc <= 2) {
|
||||
haltest_error("No action specified\n");
|
||||
return;
|
||||
}
|
||||
action = str2bthf_client_call_action_t(argv[2]);
|
||||
|
||||
/* call index */
|
||||
if (action == BTHF_CLIENT_CALL_ACTION_CHLD_1x ||
|
||||
action == BTHF_CLIENT_CALL_ACTION_CHLD_2x) {
|
||||
if (argc <= 3) {
|
||||
haltest_error("No call index specified\n");
|
||||
return;
|
||||
}
|
||||
index = atoi(argv[3]);
|
||||
}
|
||||
|
||||
EXEC(if_hf_client->handle_call_action, action, index);
|
||||
}
|
||||
|
||||
/* query list of current calls */
|
||||
static void query_current_calls_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->query_current_calls);
|
||||
}
|
||||
|
||||
/* query name of current selected operator */
|
||||
static void query_current_operator_name_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->query_current_operator_name);
|
||||
}
|
||||
|
||||
/* Retrieve subscriber information */
|
||||
static void retrieve_subscriber_info_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->retrieve_subscriber_info);
|
||||
}
|
||||
|
||||
/* Send DTMF code*/
|
||||
static void send_dtmf_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->send_dtmf, *argv[2]);
|
||||
}
|
||||
|
||||
/* Request a phone number from AG corresponding to last voice tag recorded */
|
||||
static void request_last_voice_tag_number_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXEC(if_hf_client->request_last_voice_tag_number);
|
||||
}
|
||||
|
||||
/* Closes the interface. */
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hf_client);
|
||||
|
||||
EXECV(if_hf_client->cleanup);
|
||||
if_hf_client = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(connect, "<addr>"),
|
||||
STD_METHODCH(disconnect, "<addr>"),
|
||||
STD_METHODCH(connect_audio, "<addr>"),
|
||||
STD_METHODCH(disconnect_audio, "<addr>"),
|
||||
STD_METHOD(start_voice_recognition),
|
||||
STD_METHOD(stop_voice_recognition),
|
||||
STD_METHODCH(volume_control, "<volume_type> <value>"),
|
||||
STD_METHODH(dial, "<destination_number>"),
|
||||
STD_METHODH(dial_memory, "<memory_location>"),
|
||||
STD_METHODCH(handle_call_action, "<call_action> <call_index>"),
|
||||
STD_METHOD(query_current_calls),
|
||||
STD_METHOD(query_current_operator_name),
|
||||
STD_METHOD(retrieve_subscriber_info),
|
||||
STD_METHODH(send_dtmf, "<code>"),
|
||||
STD_METHOD(request_last_voice_tag_number),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface hf_client_if = {
|
||||
.name = "handsfree_client",
|
||||
.methods = methods
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,444 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_hh.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "pollhandler.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const bthh_interface_t *if_hh = NULL;
|
||||
|
||||
SINTMAP(bthh_protocol_mode_t, -1, "(unknown)")
|
||||
DELEMENT(BTHH_REPORT_MODE),
|
||||
DELEMENT(BTHH_BOOT_MODE),
|
||||
DELEMENT(BTHH_UNSUPPORTED_MODE),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthh_report_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHH_INPUT_REPORT),
|
||||
DELEMENT(BTHH_OUTPUT_REPORT),
|
||||
DELEMENT(BTHH_FEATURE_REPORT),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthh_connection_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHH_CONN_STATE_CONNECTED),
|
||||
DELEMENT(BTHH_CONN_STATE_CONNECTING),
|
||||
DELEMENT(BTHH_CONN_STATE_DISCONNECTED),
|
||||
DELEMENT(BTHH_CONN_STATE_DISCONNECTING),
|
||||
DELEMENT(BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST),
|
||||
DELEMENT(BTHH_CONN_STATE_FAILED_KBD_FROM_HOST),
|
||||
DELEMENT(BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES),
|
||||
DELEMENT(BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER),
|
||||
DELEMENT(BTHH_CONN_STATE_FAILED_GENERIC),
|
||||
DELEMENT(BTHH_CONN_STATE_UNKNOWN),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthh_status_t, -1, "(unknown)")
|
||||
DELEMENT(BTHH_OK),
|
||||
DELEMENT(BTHH_HS_HID_NOT_READY),
|
||||
DELEMENT(BTHH_HS_INVALID_RPT_ID),
|
||||
DELEMENT(BTHH_HS_TRANS_NOT_SPT),
|
||||
DELEMENT(BTHH_HS_INVALID_PARAM),
|
||||
DELEMENT(BTHH_HS_ERROR),
|
||||
DELEMENT(BTHH_ERR),
|
||||
DELEMENT(BTHH_ERR_SDP),
|
||||
DELEMENT(BTHH_ERR_PROTO),
|
||||
DELEMENT(BTHH_ERR_DB_FULL),
|
||||
DELEMENT(BTHH_ERR_TOD_UNSPT),
|
||||
DELEMENT(BTHH_ERR_NO_RES),
|
||||
DELEMENT(BTHH_ERR_AUTH_FAILED),
|
||||
DELEMENT(BTHH_ERR_HDL),
|
||||
ENDMAP
|
||||
|
||||
static char connected_device_addr[MAX_ADDR_STR_LEN];
|
||||
/*
|
||||
* Callback for connection state change.
|
||||
* state will have one of the values from bthh_connection_state_t
|
||||
*/
|
||||
static void connection_state_cb(bt_bdaddr_t *bd_addr,
|
||||
bthh_connection_state_t state)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: bd_addr=%s connection_state=%s\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_connection_state_t2str(state));
|
||||
if (state == BTHH_CONN_STATE_CONNECTED)
|
||||
strcpy(connected_device_addr, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for virtual unplug api.
|
||||
* the status of the virtual unplug
|
||||
*/
|
||||
static void virtual_unplug_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: bd_addr=%s hh_status=%s\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_status_t2str(hh_status));
|
||||
}
|
||||
|
||||
/* Callback for Android 5.0 handshake api. */
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
static void handshake_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: bd_addr=%s hh_status=%s\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_status_t2str(hh_status));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Callback for get hid info
|
||||
* hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id,
|
||||
* version, ctry_code, len
|
||||
*/
|
||||
static void hid_info_cb(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
/* TODO: bluedroid does not seem to ever call this callback */
|
||||
haltest_info("%s: bd_addr=%s\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for get/set protocol api.
|
||||
* the protocol mode is one of the value from bthh_protocol_mode_t
|
||||
*/
|
||||
static void protocol_mode_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
|
||||
bthh_protocol_mode_t mode)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: bd_addr=%s hh_status=%s mode=%s\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_status_t2str(hh_status),
|
||||
bthh_protocol_mode_t2str(mode));
|
||||
}
|
||||
|
||||
/* Callback for get/set_idle_time api. */
|
||||
static void idle_time_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
|
||||
int idle_rate)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: bd_addr=%s hh_status=%s idle_rate=%d\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_status_t2str(hh_status), idle_rate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callback for get report api.
|
||||
* if status is ok rpt_data contains the report data
|
||||
*/
|
||||
static void get_report_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
|
||||
uint8_t *rpt_data, int rpt_size)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
/* TODO: print actual report */
|
||||
haltest_info("%s: bd_addr=%s hh_status=%s rpt_size=%d\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, addr),
|
||||
bthh_status_t2str(hh_status), rpt_size);
|
||||
}
|
||||
|
||||
static bthh_callbacks_t bthh_callbacks = {
|
||||
.size = sizeof(bthh_callbacks),
|
||||
.connection_state_cb = connection_state_cb,
|
||||
.hid_info_cb = hid_info_cb,
|
||||
.protocol_mode_cb = protocol_mode_cb,
|
||||
.idle_time_cb = idle_time_cb,
|
||||
.get_report_cb = get_report_cb,
|
||||
.virtual_unplug_cb = virtual_unplug_cb,
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
.handshake_cb = handshake_cb
|
||||
#endif
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hh);
|
||||
|
||||
EXEC(if_hh->init, &bthh_callbacks);
|
||||
}
|
||||
|
||||
/* connect */
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = (void *) connected_device_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hh->connect, &addr);
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
|
||||
/* Same completion as connect_c */
|
||||
#define disconnect_c connect_c
|
||||
|
||||
static void disconnect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hh->disconnect, &addr);
|
||||
}
|
||||
|
||||
/* virtual_unplug */
|
||||
|
||||
/* Same completion as connect_c */
|
||||
#define virtual_unplug_c connect_c
|
||||
|
||||
static void virtual_unplug_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_hh->virtual_unplug, &addr);
|
||||
}
|
||||
|
||||
/* set_info */
|
||||
|
||||
/* Same completion as connect_c */
|
||||
#define set_info_c connect_c
|
||||
|
||||
static void set_info_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
bthh_hid_info_t hid_info;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
memset(&hid_info, 0, sizeof(hid_info));
|
||||
|
||||
/*
|
||||
* This command is intentionally not supported. See comment from
|
||||
* bt_hid_info() in android/hidhost.c
|
||||
*/
|
||||
EXEC(if_hh->set_info, &addr, hid_info);
|
||||
}
|
||||
|
||||
/* get_protocol */
|
||||
|
||||
static void get_protocol_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = connected_device_addr;
|
||||
*enum_func = enum_one_string;
|
||||
} else if (argc == 4) {
|
||||
*user = TYPE_ENUM(bthh_protocol_mode_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_protocol_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
bthh_protocol_mode_t protocolMode;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc < 4) {
|
||||
haltest_error("No protocol mode specified\n");
|
||||
return;
|
||||
}
|
||||
protocolMode = str2bthh_protocol_mode_t(argv[3]);
|
||||
|
||||
EXEC(if_hh->get_protocol, &addr, protocolMode);
|
||||
}
|
||||
|
||||
/* set_protocol */
|
||||
|
||||
/* Same completion as get_protocol_c */
|
||||
#define set_protocol_c get_protocol_c
|
||||
|
||||
static void set_protocol_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
bthh_protocol_mode_t protocolMode;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc < 4) {
|
||||
haltest_error("No protocol mode specified\n");
|
||||
return;
|
||||
}
|
||||
protocolMode = str2bthh_protocol_mode_t(argv[3]);
|
||||
|
||||
EXEC(if_hh->set_protocol, &addr, protocolMode);
|
||||
}
|
||||
|
||||
/* get_report */
|
||||
|
||||
static void get_report_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = connected_device_addr;
|
||||
*enum_func = enum_one_string;
|
||||
} else if (argc == 4) {
|
||||
*user = TYPE_ENUM(bthh_report_type_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_report_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
bthh_report_type_t reportType;
|
||||
uint8_t reportId;
|
||||
int bufferSize;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc < 4) {
|
||||
haltest_error("No report type specified\n");
|
||||
return;
|
||||
}
|
||||
reportType = str2bthh_report_type_t(argv[3]);
|
||||
|
||||
if (argc < 5) {
|
||||
haltest_error("No reportId specified\n");
|
||||
return;
|
||||
}
|
||||
reportId = (uint8_t) atoi(argv[4]);
|
||||
|
||||
if (argc < 6) {
|
||||
haltest_error("No bufferSize specified\n");
|
||||
return;
|
||||
}
|
||||
bufferSize = atoi(argv[5]);
|
||||
|
||||
EXEC(if_hh->get_report, &addr, reportType, reportId, bufferSize);
|
||||
}
|
||||
|
||||
/* set_report */
|
||||
|
||||
static void set_report_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = connected_device_addr;
|
||||
*enum_func = enum_one_string;
|
||||
} else if (argc == 4) {
|
||||
*user = TYPE_ENUM(bthh_report_type_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_report_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
bthh_report_type_t reportType;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc <= 3) {
|
||||
haltest_error("No report type specified\n");
|
||||
return;
|
||||
}
|
||||
reportType = str2bthh_report_type_t(argv[3]);
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No report specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EXEC(if_hh->set_report, &addr, reportType, (char *) argv[4]);
|
||||
}
|
||||
|
||||
/* send_data */
|
||||
|
||||
static void send_data_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = connected_device_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_data_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_hh);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc <= 3) {
|
||||
haltest_error("No data to send specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EXEC(if_hh->send_data, &addr, (char *) argv[3]);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hh);
|
||||
|
||||
EXECV(if_hh->cleanup);
|
||||
}
|
||||
|
||||
/* Methods available in bthh_interface_t */
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(connect, "<addr>"),
|
||||
STD_METHODCH(disconnect, "<addr>"),
|
||||
STD_METHODCH(virtual_unplug, "<addr>"),
|
||||
STD_METHODCH(set_info, "<addr>"),
|
||||
STD_METHODCH(get_protocol, "<addr> <mode>"),
|
||||
STD_METHODCH(set_protocol, "<addr> <mode>"),
|
||||
STD_METHODCH(get_report, "<addr> <type> <report_id> <size>"),
|
||||
STD_METHODCH(set_report, "<addr> <type> <hex_encoded_report>"),
|
||||
STD_METHODCH(send_data, "<addr> <hex_encoded_data>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface hh_if = {
|
||||
.name = "hidhost",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,367 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_hl.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "pollhandler.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
SINTMAP(bthl_mdep_role_t, -1, "(unknown)")
|
||||
DELEMENT(BTHL_MDEP_ROLE_SOURCE),
|
||||
DELEMENT(BTHL_MDEP_ROLE_SINK),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthl_channel_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTHL_CHANNEL_TYPE_RELIABLE),
|
||||
DELEMENT(BTHL_CHANNEL_TYPE_STREAMING),
|
||||
DELEMENT(BTHL_CHANNEL_TYPE_ANY),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthl_app_reg_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHL_APP_REG_STATE_REG_SUCCESS),
|
||||
DELEMENT(BTHL_APP_REG_STATE_REG_FAILED),
|
||||
DELEMENT(BTHL_APP_REG_STATE_DEREG_SUCCESS),
|
||||
DELEMENT(BTHL_APP_REG_STATE_DEREG_FAILED),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(bthl_channel_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTHL_CONN_STATE_CONNECTING),
|
||||
DELEMENT(BTHL_CONN_STATE_CONNECTED),
|
||||
DELEMENT(BTHL_CONN_STATE_DISCONNECTING),
|
||||
DELEMENT(BTHL_CONN_STATE_DISCONNECTED),
|
||||
DELEMENT(BTHL_CONN_STATE_DESTROYED),
|
||||
ENDMAP
|
||||
|
||||
#define APP_ID_SIZE 20
|
||||
#define MDEP_CFG_SIZE 10
|
||||
#define CHANNEL_ID_SIZE 50
|
||||
|
||||
struct channel_info {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct mdep_cfg {
|
||||
uint8_t role;
|
||||
struct channel_info channel[CHANNEL_ID_SIZE];
|
||||
};
|
||||
|
||||
struct {
|
||||
struct mdep_cfg mdep[MDEP_CFG_SIZE];
|
||||
} app[APP_ID_SIZE];
|
||||
|
||||
const bthl_interface_t *if_hl = NULL;
|
||||
|
||||
static void app_reg_state_cb(int app_id, bthl_app_reg_state_t state)
|
||||
{
|
||||
haltest_info("%s: app_id=%d app_reg_state=%s\n", __func__,
|
||||
app_id, bthl_app_reg_state_t2str(state));
|
||||
}
|
||||
|
||||
static void channel_state_cb(int app_id, bt_bdaddr_t *bd_addr,
|
||||
int index, int channel_id,
|
||||
bthl_channel_state_t state, int fd)
|
||||
{
|
||||
char addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
haltest_info("%s: app_id=%d bd_addr=%s mdep_cfg_index=%d\n"
|
||||
"channel_id=%d channel_state=%s fd=%d\n", __func__,
|
||||
app_id, bt_bdaddr_t2str(bd_addr, addr), index,
|
||||
channel_id, bthl_channel_state_t2str(state), fd);
|
||||
|
||||
if (app_id >= APP_ID_SIZE || index >= MDEP_CFG_SIZE
|
||||
|| channel_id >= CHANNEL_ID_SIZE) {
|
||||
haltest_error("exceeds maximum limit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == BTHL_CONN_STATE_CONNECTED) {
|
||||
app[app_id].mdep[index].channel[channel_id].fd = fd;
|
||||
|
||||
/*
|
||||
* PTS expects dummy data on fd when it
|
||||
* connects in source role.
|
||||
*/
|
||||
if (app[app_id].mdep[index].role == BTHL_MDEP_ROLE_SOURCE)
|
||||
if (write(fd, "0", sizeof("0")) < 0)
|
||||
haltest_error("writing data on fd failed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == BTHL_CONN_STATE_DISCONNECTED ||
|
||||
state == BTHL_CONN_STATE_DESTROYED) {
|
||||
if (app[app_id].mdep[index].channel[channel_id].fd >= 0) {
|
||||
close(app[app_id].mdep[index].channel[channel_id].fd);
|
||||
app[app_id].mdep[index].channel[channel_id].fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bthl_callbacks_t hl_cbacks = {
|
||||
.size = sizeof(hl_cbacks),
|
||||
.app_reg_state_cb = app_reg_state_cb,
|
||||
.channel_state_cb = channel_state_cb,
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < APP_ID_SIZE; i++) {
|
||||
for (j = 0; j < MDEP_CFG_SIZE; j++) {
|
||||
app[i].mdep[j].role = 0;
|
||||
for (k = 0; k < CHANNEL_ID_SIZE; k++)
|
||||
app[i].mdep[j].channel[k].fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
EXEC(if_hl->init, &hl_cbacks);
|
||||
}
|
||||
|
||||
/* register_application */
|
||||
|
||||
static void register_application_p(int argc, const char **argv)
|
||||
{
|
||||
bthl_reg_param_t reg;
|
||||
uint16_t mdep_argc_init, mdep_argc_off;
|
||||
int app_id = -1;
|
||||
int i;
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No app name is specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 3) {
|
||||
haltest_error("No provider is specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No service name is specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 5) {
|
||||
haltest_error("No service description is specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 6) {
|
||||
haltest_error("No num of mdeps is specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(®, 0, sizeof(reg));
|
||||
|
||||
if (argc != ((atoi(argv[6]) * 4) + 7)) {
|
||||
haltest_error("mdep cfg argumetns are not proper\n");
|
||||
return;
|
||||
}
|
||||
|
||||
reg.application_name = argv[2];
|
||||
|
||||
if (strcmp("-", argv[3]))
|
||||
reg.provider_name = argv[3];
|
||||
|
||||
if (strcmp("-", argv[4]))
|
||||
reg.srv_name = argv[4];
|
||||
|
||||
if (strcmp("-", argv[5]))
|
||||
reg.srv_desp = argv[5];
|
||||
|
||||
reg.number_of_mdeps = atoi(argv[6]);
|
||||
|
||||
reg.mdep_cfg = malloc(reg.number_of_mdeps * sizeof(bthl_mdep_cfg_t));
|
||||
if (!reg.mdep_cfg) {
|
||||
haltest_error("malloc failed\n");
|
||||
return;
|
||||
}
|
||||
mdep_argc_init = 7;
|
||||
|
||||
for (i = 0; i < reg.number_of_mdeps; i++) {
|
||||
mdep_argc_off = mdep_argc_init + (4 * i);
|
||||
reg.mdep_cfg[i].mdep_role =
|
||||
str2bthl_mdep_role_t(argv[mdep_argc_off]);
|
||||
reg.mdep_cfg[i].data_type = atoi(argv[mdep_argc_off + 1]);
|
||||
reg.mdep_cfg[i].channel_type =
|
||||
str2bthl_channel_type_t(argv[mdep_argc_off + 2]);
|
||||
|
||||
if (!strcmp("-", argv[mdep_argc_off + 3])) {
|
||||
reg.mdep_cfg[i].mdep_description = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
reg.mdep_cfg[i].mdep_description = argv[mdep_argc_off + 3];
|
||||
}
|
||||
|
||||
EXEC(if_hl->register_application, ®, &app_id);
|
||||
|
||||
for (i = 0; i < reg.number_of_mdeps; i++)
|
||||
app[app_id].mdep[i].role = reg.mdep_cfg[i].mdep_role;
|
||||
|
||||
free(reg.mdep_cfg);
|
||||
}
|
||||
|
||||
/* unregister_application */
|
||||
|
||||
static void unregister_application_p(int argc, const char **argv)
|
||||
{
|
||||
uint32_t app_id;
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No app id is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
app_id = (uint32_t) atoi(argv[2]);
|
||||
|
||||
EXEC(if_hl->unregister_application, app_id);
|
||||
}
|
||||
|
||||
/* connect_channel */
|
||||
|
||||
static void connect_channel_p(int argc, const char **argv)
|
||||
{
|
||||
uint32_t app_id, mdep_cfg_index;
|
||||
int channel_id = -1;
|
||||
bt_bdaddr_t bd_addr;
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No app id is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
VERIFY_ADDR_ARG(3, &bd_addr);
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No mdep cfg index is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
app_id = (uint32_t) atoi(argv[2]);
|
||||
mdep_cfg_index = (uint32_t) atoi(argv[4]);
|
||||
|
||||
EXEC(if_hl->connect_channel, app_id, &bd_addr, mdep_cfg_index,
|
||||
&channel_id);
|
||||
}
|
||||
|
||||
/* destroy_channel */
|
||||
|
||||
static void destroy_channel_p(int argc, const char **argv)
|
||||
{
|
||||
uint32_t channel_id;
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No channel id is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
channel_id = (uint32_t) atoi(argv[2]);
|
||||
|
||||
EXEC(if_hl->destroy_channel, channel_id);
|
||||
}
|
||||
|
||||
/* close_channel */
|
||||
|
||||
static void close_channel_p(int argc, const char **argv)
|
||||
{
|
||||
uint32_t app_id;
|
||||
uint8_t index;
|
||||
int channel_id;
|
||||
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No app id is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 3) {
|
||||
haltest_error("No mdep_cfg_index is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No channel_id is specified");
|
||||
return;
|
||||
}
|
||||
|
||||
app_id = (uint32_t) atoi(argv[2]);
|
||||
if (app_id >= APP_ID_SIZE) {
|
||||
haltest_error("Wrong app_id specified: %u\n", app_id);
|
||||
return;
|
||||
}
|
||||
|
||||
index = (uint8_t) atoi(argv[3]);
|
||||
if (index >= MDEP_CFG_SIZE) {
|
||||
haltest_error("Wrong mdep cfg index: %u\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
channel_id = atoi(argv[4]);
|
||||
if (channel_id >= CHANNEL_ID_SIZE) {
|
||||
haltest_error("Wrong channel id: %u\n", channel_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (app[app_id].mdep[index].channel[channel_id].fd >= 0) {
|
||||
shutdown(app[app_id].mdep[index].channel[channel_id].fd,
|
||||
SHUT_RDWR);
|
||||
app[app_id].mdep[index].channel[channel_id].fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_hl);
|
||||
|
||||
EXECV(if_hl->cleanup);
|
||||
if_hl = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODH(register_application,
|
||||
"<app_name> <provider_name> <srv_name> <srv_descr>\n"
|
||||
"<num_of_mdeps>\n"
|
||||
"[[<mdep_role>] [<data_type>] [<channel_type>] [<mdep_descr>]]"
|
||||
"..."),
|
||||
STD_METHODH(unregister_application, "<app_id>"),
|
||||
STD_METHODH(connect_channel, "<app_id> <bd_addr> <mdep_cfg_index>"),
|
||||
STD_METHODH(destroy_channel, "<channel_id>"),
|
||||
STD_METHODH(close_channel, "<app_id> <mdep_cfg_index> <channel_id>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface hl_if = {
|
||||
.name = "hl",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,187 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <hardware/audio.h>
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_av.h>
|
||||
#include <hardware/bt_hh.h>
|
||||
#include <hardware/bt_pan.h>
|
||||
#include <hardware/bt_sock.h>
|
||||
#include <hardware/bt_hf.h>
|
||||
#include <hardware/bt_hl.h>
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
#include <hardware/bt_hf_client.h>
|
||||
#include <hardware/bt_mce.h>
|
||||
#endif
|
||||
|
||||
#include <hardware/bt_rc.h>
|
||||
#include <hardware/bt_gatt.h>
|
||||
#include <hardware/bt_gatt_types.h>
|
||||
#include <hardware/bt_gatt_client.h>
|
||||
#include <hardware/bt_gatt_server.h>
|
||||
|
||||
extern audio_hw_device_t *if_audio;
|
||||
|
||||
/* Interfaces from hal that can be populated during application lifetime */
|
||||
extern const bt_interface_t *if_bluetooth;
|
||||
extern const btav_interface_t *if_av;
|
||||
extern const btrc_interface_t *if_rc;
|
||||
extern const bthf_interface_t *if_hf;
|
||||
extern const bthh_interface_t *if_hh;
|
||||
extern const btpan_interface_t *if_pan;
|
||||
extern const bthl_interface_t *if_hl;
|
||||
extern const btsock_interface_t *if_sock;
|
||||
extern const btgatt_interface_t *if_gatt;
|
||||
extern const btgatt_server_interface_t *if_gatt_server;
|
||||
extern const btgatt_client_interface_t *if_gatt_client;
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
extern const btrc_ctrl_interface_t *if_rc_ctrl;
|
||||
extern const bthf_client_interface_t *if_hf_client;
|
||||
extern const btmce_interface_t *if_mce;
|
||||
extern const btav_interface_t *if_av_sink;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Structure defines top level interfaces that can be used in test tool
|
||||
* this will contain values as: bluetooth, av, gatt, socket, pan...
|
||||
*/
|
||||
struct interface {
|
||||
const char *name; /* interface name */
|
||||
struct method *methods; /* methods available for this interface */
|
||||
};
|
||||
|
||||
extern const struct interface audio_if;
|
||||
extern const struct interface sco_if;
|
||||
extern const struct interface bluetooth_if;
|
||||
extern const struct interface av_if;
|
||||
extern const struct interface rc_if;
|
||||
extern const struct interface gatt_if;
|
||||
extern const struct interface gatt_client_if;
|
||||
extern const struct interface gatt_server_if;
|
||||
extern const struct interface pan_if;
|
||||
extern const struct interface sock_if;
|
||||
extern const struct interface hf_if;
|
||||
extern const struct interface hh_if;
|
||||
extern const struct interface hl_if;
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
extern const struct interface ctrl_rc_if;
|
||||
extern const struct interface hf_client_if;
|
||||
extern const struct interface mce_if;
|
||||
extern const struct interface av_sink_if;
|
||||
#endif
|
||||
|
||||
/* Interfaces that will show up in tool (first part of command line) */
|
||||
extern const struct interface *interfaces[];
|
||||
|
||||
#define METHOD(name, func, comp, help) {name, func, comp, help}
|
||||
#define STD_METHOD(m) {#m, m##_p, NULL, NULL}
|
||||
#define STD_METHODC(m) {#m, m##_p, m##_c, NULL}
|
||||
#define STD_METHODH(m, h) {#m, m##_p, NULL, h}
|
||||
#define STD_METHODCH(m, h) {#m, m##_p, m##_c, h}
|
||||
#define END_METHOD {"", NULL, NULL, NULL}
|
||||
|
||||
/*
|
||||
* Function to parse argument for function, argv[0] and argv[1] are already
|
||||
* parsed before this function is called and contain interface and method name
|
||||
* up to argc - 1 arguments are finished and should be used to decide which
|
||||
* function enumeration function to return
|
||||
*/
|
||||
typedef void (*parse_and_call)(int argc, const char **argv);
|
||||
|
||||
/*
|
||||
* This is prototype of function that will return string for given number.
|
||||
* Purpose is to enumerate string for auto completion.
|
||||
* Function of this type will always be called in loop.
|
||||
* First time function is called i = 0, then if function returns non-NULL
|
||||
* it will be called again till for some value of i it will return NULL
|
||||
*/
|
||||
typedef const char *(*enum_func)(void *user, int i);
|
||||
|
||||
/*
|
||||
* This is prototype of function that when given argc, argv will
|
||||
* fill enum_func with pointer to function that will enumerate
|
||||
* parameters for argc argument, user will be passed to enum_func.
|
||||
*/
|
||||
typedef void (*tab_complete)(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user);
|
||||
|
||||
/*
|
||||
* For each method there is name and two functions to parse command line
|
||||
* and call proper hal function on.
|
||||
*/
|
||||
struct method {
|
||||
const char *name;
|
||||
parse_and_call func;
|
||||
tab_complete complete;
|
||||
const char *help;
|
||||
};
|
||||
|
||||
int haltest_error(const char *format, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
int haltest_info(const char *format, ...)__attribute__((format(printf, 1, 2)));
|
||||
int haltest_warn(const char *format, ...)__attribute__((format(printf, 1, 2)));
|
||||
|
||||
/* Enumerator for discovered devices, to be used as tab completion enum_func */
|
||||
const char *enum_devices(void *v, int i);
|
||||
const char *interface_name(void *v, int i);
|
||||
const char *command_name(void *v, int i);
|
||||
void add_remote_device(const bt_bdaddr_t *addr);
|
||||
bool close_hw_bt_dev(void);
|
||||
|
||||
const struct interface *get_interface(const char *name);
|
||||
struct method *get_method(struct method *methods, const char *name);
|
||||
struct method *get_command(const char *name);
|
||||
const struct method *get_interface_method(const char *iname,
|
||||
const char *mname);
|
||||
|
||||
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
||||
|
||||
/* Helper macro for executing function on interface and printing BT_STATUS */
|
||||
#define EXEC(f, ...) \
|
||||
{ \
|
||||
if (f) { \
|
||||
int err = f(__VA_ARGS__); \
|
||||
haltest_info("%s: %s\n", #f, bt_status_t2str(err)); \
|
||||
} else { \
|
||||
haltest_info("%s is NULL\n", #f); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Helper macro for executing void function on interface */
|
||||
#define EXECV(f, ...) \
|
||||
{ \
|
||||
(void) f(__VA_ARGS__); \
|
||||
haltest_info("%s: void\n", #f); \
|
||||
}
|
||||
|
||||
#define RETURN_IF_NULL(x) \
|
||||
do { if (!x) { haltest_error("%s is NULL\n", #x); return; } } while (0)
|
||||
|
||||
#define VERIFY_ADDR_ARG(n, adr) \
|
||||
do { \
|
||||
if (n < argc) {\
|
||||
str2bt_bdaddr_t(argv[n], adr); \
|
||||
} else { \
|
||||
haltest_error("No address specified\n");\
|
||||
return;\
|
||||
} \
|
||||
} while (0)
|
||||
@@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btmce_interface_t *if_mce = NULL;
|
||||
|
||||
/*
|
||||
* Callback for get_remote_mas_instances
|
||||
*/
|
||||
static void btmce_remote_mas_instances_cb(bt_status_t status,
|
||||
bt_bdaddr_t *bd_addr,
|
||||
int num_instances,
|
||||
btmce_mas_instance_t *instances)
|
||||
{
|
||||
int i;
|
||||
|
||||
haltest_info("%s: status=%s bd_addr=%s num_instance=%d\n", __func__,
|
||||
bt_status_t2str(status), bdaddr2str(bd_addr),
|
||||
num_instances);
|
||||
|
||||
for (i = 0; i < num_instances; i++)
|
||||
haltest_info("id=%d scn=%d msg_types=%d name=%s\n",
|
||||
instances[i].id, instances[i].scn,
|
||||
instances[i].msg_types, instances[i].p_name);
|
||||
}
|
||||
|
||||
static btmce_callbacks_t mce_cbacks = {
|
||||
.size = sizeof(mce_cbacks),
|
||||
.remote_mas_instances_cb = btmce_remote_mas_instances_cb,
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_mce);
|
||||
|
||||
EXEC(if_mce->init, &mce_cbacks);
|
||||
}
|
||||
|
||||
static void get_remote_mas_instances_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
/* search for MAS instances on remote device */
|
||||
|
||||
static void get_remote_mas_instances_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_mce);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_mce->get_remote_mas_instances, &addr);
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(get_remote_mas_instances, "<addr>"),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface mce_if = {
|
||||
.name = "mce",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,203 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btpan_interface_t *if_pan = NULL;
|
||||
|
||||
typedef int btpan_role_t;
|
||||
|
||||
SINTMAP(btpan_role_t, -1, "(unknown)")
|
||||
DELEMENT(BTPAN_ROLE_NONE),
|
||||
DELEMENT(BTPAN_ROLE_PANNAP),
|
||||
DELEMENT(BTPAN_ROLE_PANU),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btpan_connection_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTPAN_STATE_CONNECTED),
|
||||
DELEMENT(BTPAN_STATE_CONNECTING),
|
||||
DELEMENT(BTPAN_STATE_DISCONNECTED),
|
||||
DELEMENT(BTPAN_STATE_DISCONNECTING),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btpan_control_state_t, -1, "(unknown)")
|
||||
DELEMENT(BTPAN_STATE_ENABLED),
|
||||
DELEMENT(BTPAN_STATE_DISABLED),
|
||||
ENDMAP
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
static void control_state_cb(btpan_control_state_t state, int local_role,
|
||||
bt_status_t error, const char *ifname)
|
||||
#else
|
||||
static void control_state_cb(btpan_control_state_t state, bt_status_t error,
|
||||
int local_role, const char *ifname)
|
||||
#endif
|
||||
{
|
||||
haltest_info("%s: state=%s error=%s local_role=%s ifname=%s\n",
|
||||
__func__, btpan_control_state_t2str(state),
|
||||
bt_status_t2str(error), btpan_role_t2str(local_role),
|
||||
ifname);
|
||||
}
|
||||
|
||||
static char last_used_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
static void connection_state_cb(btpan_connection_state_t state,
|
||||
bt_status_t error, const bt_bdaddr_t *bd_addr,
|
||||
int local_role, int remote_role)
|
||||
{
|
||||
haltest_info("%s: state=%s error=%s bd_addr=%s local_role=%s remote_role=%s\n",
|
||||
__func__, btpan_connection_state_t2str(state),
|
||||
bt_status_t2str(error),
|
||||
bt_bdaddr_t2str(bd_addr, last_used_addr),
|
||||
btpan_role_t2str(local_role),
|
||||
btpan_role_t2str(remote_role));
|
||||
}
|
||||
|
||||
static btpan_callbacks_t pan_cbacks = {
|
||||
.size = sizeof(pan_cbacks),
|
||||
.control_state_cb = control_state_cb,
|
||||
.connection_state_cb = connection_state_cb
|
||||
};
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_pan);
|
||||
|
||||
EXEC(if_pan->init, &pan_cbacks);
|
||||
}
|
||||
|
||||
/* enable */
|
||||
|
||||
static void enable_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(btpan_role_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_p(int argc, const char **argv)
|
||||
{
|
||||
int local_role;
|
||||
|
||||
RETURN_IF_NULL(if_pan);
|
||||
|
||||
/* local role */
|
||||
if (argc < 3) {
|
||||
haltest_error("No local mode specified\n");
|
||||
return;
|
||||
}
|
||||
local_role = str2btpan_role_t(argv[2]);
|
||||
if (local_role == -1)
|
||||
local_role = atoi(argv[2]);
|
||||
|
||||
EXEC(if_pan->enable, local_role);
|
||||
}
|
||||
|
||||
/* get_local_role */
|
||||
|
||||
static void get_local_role_p(int argc, const char **argv)
|
||||
{
|
||||
int local_role;
|
||||
|
||||
RETURN_IF_NULL(if_pan);
|
||||
|
||||
local_role = if_pan->get_local_role();
|
||||
haltest_info("local_role: %s\n", btpan_role_t2str(local_role));
|
||||
}
|
||||
|
||||
/* connect */
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
} else if (argc == 4 || argc == 5) {
|
||||
*user = TYPE_ENUM(btpan_role_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
int local_role;
|
||||
int remote_role;
|
||||
|
||||
RETURN_IF_NULL(if_pan);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
/* local role */
|
||||
if (argc < 4) {
|
||||
haltest_error("No local mode specified\n");
|
||||
return;
|
||||
}
|
||||
local_role = str2btpan_role_t(argv[3]);
|
||||
if (local_role == -1)
|
||||
local_role = atoi(argv[3]);
|
||||
|
||||
/* remote role */
|
||||
if (argc < 5) {
|
||||
haltest_error("No remote mode specified\n");
|
||||
return;
|
||||
}
|
||||
remote_role = str2btpan_role_t(argv[4]);
|
||||
if (remote_role == -1)
|
||||
remote_role = atoi(argv[4]);
|
||||
|
||||
EXEC(if_pan->connect, &addr, local_role, remote_role);
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
|
||||
static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = last_used_addr;
|
||||
*enum_func = enum_one_string;
|
||||
}
|
||||
}
|
||||
|
||||
static void disconnect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
|
||||
RETURN_IF_NULL(if_pan);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
EXEC(if_pan->disconnect, &addr);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_pan);
|
||||
|
||||
EXECV(if_pan->cleanup);
|
||||
if_pan = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(connect, "<addr> <local_role> <remote_role>"),
|
||||
STD_METHODCH(enable, "<local_role>"),
|
||||
STD_METHOD(get_local_role),
|
||||
STD_METHODCH(disconnect, "<addr>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface pan_if = {
|
||||
.name = "pan",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_rc.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "pollhandler.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btrc_ctrl_interface_t *if_rc_ctrl = NULL;
|
||||
static char last_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
static void passthrough_rsp_cb(int id, int key_state)
|
||||
{
|
||||
haltest_info("%s: id=%d key_state=%d\n", __func__, id, key_state);
|
||||
}
|
||||
|
||||
static void connection_state_cb(bool state, bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
haltest_info("%s: state=%s bd_addr=%s\n", __func__,
|
||||
state ? "true" : "false",
|
||||
bt_bdaddr_t2str(bd_addr, last_addr));
|
||||
}
|
||||
|
||||
static btrc_ctrl_callbacks_t rc_ctrl_cbacks = {
|
||||
.size = sizeof(rc_ctrl_cbacks),
|
||||
.passthrough_rsp_cb = passthrough_rsp_cb,
|
||||
.connection_state_cb = connection_state_cb,
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_rc_ctrl);
|
||||
|
||||
EXEC(if_rc_ctrl->init, &rc_ctrl_cbacks);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_rc_ctrl);
|
||||
|
||||
EXECV(if_rc_ctrl->cleanup);
|
||||
if_rc_ctrl = NULL;
|
||||
}
|
||||
|
||||
/* send_pass_through_cmd */
|
||||
static void send_pass_through_cmd_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = NULL;
|
||||
*enum_func = enum_devices;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_pass_through_cmd_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
uint8_t key_code, key_state;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
VERIFY_ADDR_ARG(2, &addr);
|
||||
|
||||
if (argc < 4) {
|
||||
haltest_error("No key code specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
key_code = (uint8_t) atoi(argv[3]);
|
||||
|
||||
if (argc < 5) {
|
||||
haltest_error("No key state specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
key_state = (uint8_t) atoi(argv[4]);
|
||||
|
||||
EXEC(if_rc_ctrl->send_pass_through_cmd, &addr, key_code, key_state);
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(send_pass_through_cmd, "<bd_addr> <key_code> <key_state>"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface ctrl_rc_if = {
|
||||
.name = "rc-ctrl",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,390 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/bluetooth.h>
|
||||
#include <hardware/bt_hh.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "pollhandler.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btrc_interface_t *if_rc = NULL;
|
||||
|
||||
SINTMAP(btrc_play_status_t, -1, "(unknown)")
|
||||
DELEMENT(BTRC_PLAYSTATE_STOPPED),
|
||||
DELEMENT(BTRC_PLAYSTATE_PLAYING),
|
||||
DELEMENT(BTRC_PLAYSTATE_PAUSED),
|
||||
DELEMENT(BTRC_PLAYSTATE_FWD_SEEK),
|
||||
DELEMENT(BTRC_PLAYSTATE_REV_SEEK),
|
||||
DELEMENT(BTRC_PLAYSTATE_ERROR),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btrc_media_attr_t, -1, "(unknown)")
|
||||
DELEMENT(BTRC_MEDIA_ATTR_TITLE),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_ARTIST),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_ALBUM),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_TRACK_NUM),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_NUM_TRACKS),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_GENRE),
|
||||
DELEMENT(BTRC_MEDIA_ATTR_PLAYING_TIME),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btrc_status_t, -1, "(unknown)")
|
||||
DELEMENT(BTRC_STS_BAD_CMD),
|
||||
DELEMENT(BTRC_STS_BAD_PARAM),
|
||||
DELEMENT(BTRC_STS_NOT_FOUND),
|
||||
DELEMENT(BTRC_STS_INTERNAL_ERR),
|
||||
DELEMENT(BTRC_STS_NO_ERROR),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btrc_event_id_t, -1, "(unknown)")
|
||||
DELEMENT(BTRC_EVT_PLAY_STATUS_CHANGED),
|
||||
DELEMENT(BTRC_EVT_TRACK_CHANGE),
|
||||
DELEMENT(BTRC_EVT_TRACK_REACHED_END),
|
||||
DELEMENT(BTRC_EVT_TRACK_REACHED_START),
|
||||
DELEMENT(BTRC_EVT_PLAY_POS_CHANGED),
|
||||
DELEMENT(BTRC_EVT_APP_SETTINGS_CHANGED),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(btrc_notification_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTRC_NOTIFICATION_TYPE_INTERIM),
|
||||
DELEMENT(BTRC_NOTIFICATION_TYPE_CHANGED),
|
||||
ENDMAP
|
||||
|
||||
static char last_addr[MAX_ADDR_STR_LEN];
|
||||
|
||||
static void remote_features_cb(bt_bdaddr_t *bd_addr,
|
||||
btrc_remote_features_t features)
|
||||
{
|
||||
haltest_info("%s: remote_bd_addr=%s features=%u\n", __func__,
|
||||
bt_bdaddr_t2str(bd_addr, last_addr), features);
|
||||
}
|
||||
|
||||
static void get_play_status_cb(void)
|
||||
{
|
||||
haltest_info("%s\n", __func__);
|
||||
}
|
||||
|
||||
static void list_player_app_attr_cb(void)
|
||||
{
|
||||
haltest_info("%s\n", __func__);
|
||||
}
|
||||
|
||||
static void list_player_app_values_cb(btrc_player_attr_t attr_id)
|
||||
{
|
||||
haltest_info("%s, attr_id=%d\n", __func__, attr_id);
|
||||
}
|
||||
|
||||
static void get_player_app_value_cb(uint8_t num_attr,
|
||||
btrc_player_attr_t *p_attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
haltest_info("%s, num_attr=%d\n", __func__, num_attr);
|
||||
|
||||
for (i = 0; i < num_attr; i++)
|
||||
haltest_info("attribute=%u\n", p_attrs[i]);
|
||||
}
|
||||
|
||||
static void get_player_app_attrs_text_cb(uint8_t num_attr,
|
||||
btrc_player_attr_t *p_attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
haltest_info("%s, num_attr=%d\n", __func__, num_attr);
|
||||
|
||||
for (i = 0; i < num_attr; i++)
|
||||
haltest_info("attribute=%u\n", p_attrs[i]);
|
||||
|
||||
}
|
||||
|
||||
static void get_player_app_values_text_cb(uint8_t attr_id, uint8_t num_val,
|
||||
uint8_t *p_vals)
|
||||
{
|
||||
haltest_info("%s, attr_id=%d num_val=%d values=%p\n", __func__,
|
||||
attr_id, num_val, p_vals);
|
||||
}
|
||||
|
||||
static void set_player_app_value_cb(btrc_player_settings_t *p_vals)
|
||||
{
|
||||
int i;
|
||||
|
||||
haltest_info("%s, num_attr=%u\n", __func__, p_vals->num_attr);
|
||||
|
||||
for (i = 0; i < p_vals->num_attr; i++)
|
||||
haltest_info("attr id=%u, values=%u\n", p_vals->attr_ids[i],
|
||||
p_vals->attr_values[i]);
|
||||
}
|
||||
|
||||
static void get_element_attr_cb(uint8_t num_attr, btrc_media_attr_t *attrs)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
haltest_info("%s, num_of_attributes=%d\n", __func__, num_attr);
|
||||
|
||||
for (i = 0; i < num_attr; i++)
|
||||
haltest_info("attr id=%s\n", btrc_media_attr_t2str(attrs[i]));
|
||||
}
|
||||
|
||||
static void register_notification_cb(btrc_event_id_t event_id, uint32_t param)
|
||||
{
|
||||
haltest_info("%s, event=%u param=%u\n", __func__, event_id, param);
|
||||
}
|
||||
|
||||
static void volume_change_cb(uint8_t volume, uint8_t ctype)
|
||||
{
|
||||
haltest_info("%s, volume=%d ctype=%d\n", __func__, volume, ctype);
|
||||
}
|
||||
|
||||
static void passthrough_cmd_cb(int id, int key_state)
|
||||
{
|
||||
haltest_info("%s, id=%d key_state=%d\n", __func__, id, key_state);
|
||||
}
|
||||
|
||||
static btrc_callbacks_t rc_cbacks = {
|
||||
.size = sizeof(rc_cbacks),
|
||||
.remote_features_cb = remote_features_cb,
|
||||
.get_play_status_cb = get_play_status_cb,
|
||||
.list_player_app_attr_cb = list_player_app_attr_cb,
|
||||
.list_player_app_values_cb = list_player_app_values_cb,
|
||||
.get_player_app_value_cb = get_player_app_value_cb,
|
||||
.get_player_app_attrs_text_cb = get_player_app_attrs_text_cb,
|
||||
.get_player_app_values_text_cb = get_player_app_values_text_cb,
|
||||
.set_player_app_value_cb = set_player_app_value_cb,
|
||||
.get_element_attr_cb = get_element_attr_cb,
|
||||
.register_notification_cb = register_notification_cb,
|
||||
.volume_change_cb = volume_change_cb,
|
||||
.passthrough_cmd_cb = passthrough_cmd_cb,
|
||||
};
|
||||
|
||||
/* init */
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
EXEC(if_rc->init, &rc_cbacks);
|
||||
}
|
||||
|
||||
/* get_play_status_rsp */
|
||||
|
||||
static void get_play_status_rsp_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(btrc_play_status_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_play_status_rsp_p(int argc, const char **argv)
|
||||
{
|
||||
btrc_play_status_t play_status;
|
||||
uint32_t song_len, song_pos;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No play status specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 3) {
|
||||
haltest_error("No song length specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No song position specified");
|
||||
return;
|
||||
}
|
||||
|
||||
play_status = str2btrc_play_status_t(argv[2]);
|
||||
song_len = (uint32_t) atoi(argv[3]);
|
||||
song_pos = (uint32_t) atoi(argv[4]);
|
||||
|
||||
EXEC(if_rc->get_play_status_rsp, play_status, song_len, song_pos);
|
||||
}
|
||||
|
||||
/* get_element_attr_rsp */
|
||||
|
||||
static void get_element_attr_rsp_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 4) {
|
||||
*user = TYPE_ENUM(btrc_media_attr_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_element_attr_rsp_p(int argc, const char **argv)
|
||||
{
|
||||
uint8_t num_attr;
|
||||
btrc_element_attr_val_t attrs;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No number of attributes specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc <= 4) {
|
||||
haltest_error("No attr id and value specified");
|
||||
return;
|
||||
}
|
||||
|
||||
num_attr = (uint8_t) atoi(argv[2]);
|
||||
attrs.attr_id = str2btrc_media_attr_t(argv[3]);
|
||||
strcpy((char *)attrs.text, argv[4]);
|
||||
|
||||
EXEC(if_rc->get_element_attr_rsp, num_attr, &attrs);
|
||||
}
|
||||
|
||||
/* set_volume */
|
||||
|
||||
static void set_volume_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
}
|
||||
|
||||
static void set_volume_p(int argc, const char **argv)
|
||||
{
|
||||
uint8_t volume;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No volume specified");
|
||||
return;
|
||||
}
|
||||
|
||||
volume = (uint8_t) atoi(argv[2]);
|
||||
|
||||
EXEC(if_rc->set_volume, volume);
|
||||
}
|
||||
|
||||
/* set_player_app_value_rsp */
|
||||
|
||||
static void set_player_app_value_rsp_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(btrc_status_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_player_app_value_rsp_p(int argc, const char **argv)
|
||||
{
|
||||
btrc_status_t rsp_status;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
if (argc <= 2) {
|
||||
haltest_error("No response status specified");
|
||||
return;
|
||||
}
|
||||
|
||||
rsp_status = str2btrc_status_t(argv[2]);
|
||||
|
||||
EXEC(if_rc->set_player_app_value_rsp, rsp_status);
|
||||
}
|
||||
|
||||
/* register_notification_rsp */
|
||||
|
||||
static void register_notification_rsp_c(int argc, const char **argv,
|
||||
enum_func *enum_func, void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(btrc_event_id_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
*user = TYPE_ENUM(btrc_notification_type_t);
|
||||
*enum_func = enum_defines;
|
||||
}
|
||||
}
|
||||
|
||||
static void register_notification_rsp_p(int argc, const char **argv)
|
||||
{
|
||||
btrc_event_id_t event_id;
|
||||
btrc_notification_type_t type;
|
||||
btrc_register_notification_t reg;
|
||||
uint32_t song_pos;
|
||||
uint64_t track;
|
||||
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
memset(®, 0, sizeof(reg));
|
||||
event_id = str2btrc_event_id_t(argv[2]);
|
||||
type = str2btrc_notification_type_t(argv[3]);
|
||||
|
||||
switch (event_id) {
|
||||
case BTRC_EVT_PLAY_STATUS_CHANGED:
|
||||
reg.play_status = str2btrc_play_status_t(argv[4]);
|
||||
break;
|
||||
|
||||
case BTRC_EVT_TRACK_CHANGE:
|
||||
track = strtoull(argv[5], NULL, 10);
|
||||
memcpy(reg.track, &track, sizeof(btrc_uid_t));
|
||||
break;
|
||||
|
||||
case BTRC_EVT_TRACK_REACHED_END:
|
||||
case BTRC_EVT_TRACK_REACHED_START:
|
||||
break;
|
||||
|
||||
case BTRC_EVT_PLAY_POS_CHANGED:
|
||||
song_pos = strtoul(argv[4], NULL, 10);
|
||||
memcpy(®.song_pos, &song_pos, sizeof(uint32_t));
|
||||
break;
|
||||
|
||||
case BTRC_EVT_APP_SETTINGS_CHANGED:
|
||||
haltest_error("not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
EXEC(if_rc->register_notification_rsp, event_id, type, ®);
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_rc);
|
||||
|
||||
EXECV(if_rc->cleanup);
|
||||
if_rc = NULL;
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHODCH(get_play_status_rsp,
|
||||
"<play_status> <song_len> <song_pos>"),
|
||||
STD_METHODCH(get_element_attr_rsp, "<num_attr> <attrs_id> <value>"),
|
||||
STD_METHODCH(set_player_app_value_rsp, "<rsp_status>"),
|
||||
STD_METHODCH(set_volume, "<volume>"),
|
||||
STD_METHODCH(register_notification_rsp,
|
||||
"<event_id> <type> <respective_data...>\n"
|
||||
"BTRC_EVT_PLAY_STATUS_CHANGED <type> <play_status>\n"
|
||||
"BTRC_EVT_TRACK_CHANGE <type> <track>\n"
|
||||
"BTRC_EVT_TRACK_REACHED_END <type>\n"
|
||||
"BTRC_EVT_TRACK_REACHED_START <type>\n"
|
||||
"BTRC_EVT_PLAY_POS_CHANGED <type> <song_pos>\n"),
|
||||
STD_METHOD(cleanup),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface rc_if = {
|
||||
.name = "rc",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,805 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
audio_hw_device_t *if_audio_sco = NULL;
|
||||
static struct audio_stream_out *stream_out = NULL;
|
||||
static struct audio_stream_in *stream_in = NULL;
|
||||
|
||||
static size_t buffer_size = 0;
|
||||
static size_t buffer_size_in = 0;
|
||||
static pthread_t play_thread = 0;
|
||||
static pthread_mutex_t outstream_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
enum state {
|
||||
STATE_STOPPED,
|
||||
STATE_STOPPING,
|
||||
STATE_PLAYING,
|
||||
STATE_SUSPENDED,
|
||||
STATE_MAX
|
||||
};
|
||||
|
||||
SINTMAP(audio_channel_mask_t, -1, "(AUDIO_CHANNEL_INVALID)")
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_BACK_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SIDE_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_MONO),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_STEREO),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD),
|
||||
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_SURROUND),
|
||||
#else
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD_BACK),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_QUAD_SIDE),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_BACK),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
|
||||
#endif
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_5POINT1),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_7POINT1),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_ALL),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||
ENDMAP
|
||||
|
||||
SINTMAP(audio_format_t, -1, "(AUDIO_FORMAT_INVALID)")
|
||||
DELEMENT(AUDIO_FORMAT_DEFAULT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM),
|
||||
DELEMENT(AUDIO_FORMAT_MP3),
|
||||
DELEMENT(AUDIO_FORMAT_AMR_NB),
|
||||
DELEMENT(AUDIO_FORMAT_AMR_WB),
|
||||
DELEMENT(AUDIO_FORMAT_AAC),
|
||||
DELEMENT(AUDIO_FORMAT_HE_AAC_V1),
|
||||
DELEMENT(AUDIO_FORMAT_HE_AAC_V2),
|
||||
DELEMENT(AUDIO_FORMAT_VORBIS),
|
||||
DELEMENT(AUDIO_FORMAT_MAIN_MASK),
|
||||
DELEMENT(AUDIO_FORMAT_SUB_MASK),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_16_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_8_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_32_BIT),
|
||||
DELEMENT(AUDIO_FORMAT_PCM_8_24_BIT),
|
||||
ENDMAP
|
||||
|
||||
static int current_state = STATE_STOPPED;
|
||||
|
||||
#define SAMPLERATE 44100
|
||||
static short sample[SAMPLERATE];
|
||||
static uint16_t sample_pos;
|
||||
|
||||
static void init_p(int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
const hw_module_t *module;
|
||||
audio_hw_device_t *device;
|
||||
|
||||
err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "sco", &module);
|
||||
if (err) {
|
||||
haltest_error("hw_get_module_by_class returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = audio_hw_device_open(module, &device);
|
||||
if (err) {
|
||||
haltest_error("audio_hw_device_open returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if_audio_sco = device;
|
||||
}
|
||||
|
||||
static int feed_from_file(short *buffer, void *data)
|
||||
{
|
||||
FILE *in = data;
|
||||
return fread(buffer, buffer_size, 1, in);
|
||||
}
|
||||
|
||||
static int feed_from_generator(short *buffer, void *data)
|
||||
{
|
||||
size_t i = 0;
|
||||
float volume = 0.5;
|
||||
float *freq = data;
|
||||
float f = 1;
|
||||
|
||||
if (freq)
|
||||
f = *freq;
|
||||
|
||||
/* buffer_size is in bytes but we are using buffer of shorts (2 bytes)*/
|
||||
for (i = 0; i < buffer_size / sizeof(*buffer) - 1;) {
|
||||
if (sample_pos >= SAMPLERATE)
|
||||
sample_pos = sample_pos % SAMPLERATE;
|
||||
|
||||
/* Use the same sample for both channels */
|
||||
buffer[i++] = sample[sample_pos] * volume;
|
||||
buffer[i++] = sample[sample_pos] * volume;
|
||||
|
||||
sample_pos += f;
|
||||
}
|
||||
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
static int feed_from_in(short *buffer, void *data)
|
||||
{
|
||||
return stream_in->read(stream_in, buffer, buffer_size_in);
|
||||
}
|
||||
|
||||
static void prepare_sample(void)
|
||||
{
|
||||
int x;
|
||||
double s;
|
||||
|
||||
haltest_info("Preparing audio sample...\n");
|
||||
|
||||
for (x = 0; x < SAMPLERATE; x++) {
|
||||
/* prepare sinusoidal 1Hz sample */
|
||||
s = (2.0 * 3.14159) * ((double)x / SAMPLERATE);
|
||||
s = sin(s);
|
||||
|
||||
/* remap <-1, 1> to signed 16bit PCM range */
|
||||
sample[x] = s * 32767;
|
||||
}
|
||||
|
||||
sample_pos = 0;
|
||||
}
|
||||
|
||||
static void mono_to_stereo_pcm16(const int16_t *in, int16_t *out, size_t samples)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
out[2 * i] = in[i];
|
||||
out[2 * i + 1] = in[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void *playback_thread(void *data)
|
||||
{
|
||||
int (*filbuff_cb) (short*, void*);
|
||||
short buffer[buffer_size / sizeof(short)];
|
||||
short buffer_in[buffer_size_in / sizeof(short)];
|
||||
size_t len = 0;
|
||||
ssize_t w_len = 0;
|
||||
FILE *in = data;
|
||||
void *cb_data = NULL;
|
||||
float freq = 440.0;
|
||||
|
||||
/* Use file or fall back to generator */
|
||||
if (in) {
|
||||
if (data == stream_in)
|
||||
filbuff_cb = feed_from_in;
|
||||
else {
|
||||
filbuff_cb = feed_from_file;
|
||||
cb_data = in;
|
||||
}
|
||||
} else {
|
||||
prepare_sample();
|
||||
filbuff_cb = feed_from_generator;
|
||||
cb_data = &freq;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_PLAYING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
do {
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
|
||||
if (current_state == STATE_STOPPING) {
|
||||
haltest_info("Detected stopping\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
break;
|
||||
} else if (current_state == STATE_SUSPENDED) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
usleep(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (data && data == stream_in) {
|
||||
int chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
|
||||
int chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
|
||||
|
||||
len = filbuff_cb(buffer_in, cb_data);
|
||||
|
||||
if (chan_in == 1 && chan_out == 2) {
|
||||
mono_to_stereo_pcm16(buffer_in,
|
||||
buffer,
|
||||
buffer_size_in / 2);
|
||||
}
|
||||
} else
|
||||
len = filbuff_cb(buffer, cb_data);
|
||||
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
if (!stream_out) {
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
w_len = stream_out->write(stream_out, buffer, buffer_size);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
} while (len && w_len > 0);
|
||||
|
||||
if (in && data != stream_in)
|
||||
fclose(in);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_STOPPED;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
haltest_info("Done playing.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void write_stereo_pcm16(const short *input, size_t len, FILE *out)
|
||||
{
|
||||
short sample[2];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
sample[0] = input[i];
|
||||
sample[1] = input[i];
|
||||
|
||||
fwrite(sample, sizeof(sample), 1, out);
|
||||
}
|
||||
}
|
||||
|
||||
static void *read_thread(void *data)
|
||||
{
|
||||
int (*filbuff_cb) (short*, void*) = feed_from_in;
|
||||
short buffer[buffer_size_in / sizeof(short)];
|
||||
ssize_t len = 0;
|
||||
void *cb_data = NULL;
|
||||
FILE *out = data;
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_PLAYING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
do {
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
|
||||
if (current_state == STATE_STOPPING) {
|
||||
haltest_info("Detected stopping\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
break;
|
||||
} else if (current_state == STATE_SUSPENDED) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
usleep(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
len = filbuff_cb(buffer, cb_data);
|
||||
if (len < 0) {
|
||||
haltest_error("Error receiving SCO data");
|
||||
break;
|
||||
}
|
||||
|
||||
haltest_info("Read %zd bytes\n", len);
|
||||
|
||||
if (out) {
|
||||
write_stereo_pcm16(buffer, len, out);
|
||||
haltest_info("Written %zd bytes\n", len * 2);
|
||||
}
|
||||
} while (len);
|
||||
|
||||
if (out)
|
||||
fclose(out);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
current_state = STATE_STOPPED;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
haltest_info("Done reading.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void play_p(int argc, const char **argv)
|
||||
{
|
||||
const char *fname = NULL;
|
||||
FILE *in = NULL;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_error("Invalid audio file path.\n");
|
||||
haltest_info("Using sound generator.\n");
|
||||
} else {
|
||||
fname = argv[2];
|
||||
in = fopen(fname, "r");
|
||||
|
||||
if (in == NULL) {
|
||||
haltest_error("Cannot open file: %s\n", fname);
|
||||
return;
|
||||
}
|
||||
haltest_info("Playing file: %s\n", fname);
|
||||
}
|
||||
|
||||
if (buffer_size == 0) {
|
||||
haltest_error("Invalid buffer size. Was stream_out opened?\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
haltest_error("Already playing or stream suspended!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
goto fail;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
|
||||
haltest_error("Cannot create playback thread!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return;
|
||||
fail:
|
||||
if (in)
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static void loop_p(int argc, const char **argv)
|
||||
{
|
||||
int chan_out, chan_in;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
RETURN_IF_NULL(stream_in);
|
||||
|
||||
chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
|
||||
chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
|
||||
|
||||
if (!buffer_size || !buffer_size_in) {
|
||||
haltest_error("Invalid buffer sizes. Streams opened\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_size / chan_out != buffer_size_in / chan_in) {
|
||||
haltest_error("read/write buffers differ, not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
haltest_error("Already playing or stream suspended!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (pthread_create(&play_thread, NULL, playback_thread,
|
||||
stream_in) != 0)
|
||||
haltest_error("Cannot create playback thread!\n");
|
||||
}
|
||||
|
||||
static void read_p(int argc, const char **argv)
|
||||
{
|
||||
const char *fname = NULL;
|
||||
FILE *out = NULL;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_in);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
haltest_error("Already playing or stream suspended!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_error("Invalid audio file path.\n");
|
||||
haltest_info("Using read and through away\n");
|
||||
} else {
|
||||
fname = argv[2];
|
||||
out = fopen(fname, "w");
|
||||
if (!out) {
|
||||
haltest_error("Cannot open file: %s\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
haltest_info("Reading to file: %s\n", fname);
|
||||
}
|
||||
|
||||
if (!buffer_size_in) {
|
||||
haltest_error("Invalid buffer size.\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (pthread_create(&play_thread, NULL, read_thread, out) != 0) {
|
||||
haltest_error("Cannot create playback thread!\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
failed:
|
||||
if (out)
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
static void stop_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(play_thread);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream_out) {
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
stream_out->common.standby(&stream_out->common);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
}
|
||||
|
||||
current_state = STATE_STOPPING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
pthread_join(play_thread, NULL);
|
||||
play_thread = 0;
|
||||
|
||||
haltest_info("Ended %s\n", __func__);
|
||||
}
|
||||
|
||||
static void open_output_stream_p(int argc, const char **argv)
|
||||
{
|
||||
struct audio_config *config;
|
||||
int err;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_PLAYING) {
|
||||
haltest_error("Already playing!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_info("No sampling rate specified. Use default conf\n");
|
||||
config = NULL;
|
||||
} else {
|
||||
config = calloc(1, sizeof(struct audio_config));
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
config->sample_rate = atoi(argv[2]);
|
||||
config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
|
||||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||||
}
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
err = if_audio_sco->open_output_stream(if_audio_sco,
|
||||
0,
|
||||
AUDIO_DEVICE_OUT_ALL_SCO,
|
||||
AUDIO_OUTPUT_FLAG_NONE,
|
||||
config,
|
||||
&stream_out, NULL);
|
||||
#else
|
||||
err = if_audio_sco->open_output_stream(if_audio_sco,
|
||||
0,
|
||||
AUDIO_DEVICE_OUT_ALL_SCO,
|
||||
AUDIO_OUTPUT_FLAG_NONE,
|
||||
config,
|
||||
&stream_out);
|
||||
#endif
|
||||
if (err < 0) {
|
||||
haltest_error("open output stream returned %d\n", err);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
|
||||
if (buffer_size == 0)
|
||||
haltest_error("Invalid buffer size received!\n");
|
||||
else
|
||||
haltest_info("Using buffer size: %zu\n", buffer_size);
|
||||
failed:
|
||||
if (config)
|
||||
free(config);
|
||||
}
|
||||
|
||||
static void close_output_stream_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (play_thread)
|
||||
stop_p(argc, argv);
|
||||
|
||||
if_audio_sco->close_output_stream(if_audio_sco, stream_out);
|
||||
|
||||
stream_out = NULL;
|
||||
buffer_size = 0;
|
||||
}
|
||||
|
||||
static void open_input_stream_p(int argc, const char **argv)
|
||||
{
|
||||
struct audio_config *config;
|
||||
int err;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_PLAYING) {
|
||||
haltest_error("Already playing!\n");
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_info("No sampling rate specified. Use default conf\n");
|
||||
config = NULL;
|
||||
} else {
|
||||
config = calloc(1, sizeof(struct audio_config));
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
config->sample_rate = atoi(argv[2]);
|
||||
config->channel_mask = AUDIO_CHANNEL_OUT_MONO;
|
||||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||||
}
|
||||
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
err = if_audio_sco->open_input_stream(if_audio_sco,
|
||||
0,
|
||||
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
|
||||
config,
|
||||
&stream_in, 0, NULL, 0);
|
||||
#else
|
||||
err = if_audio_sco->open_input_stream(if_audio_sco,
|
||||
0,
|
||||
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
|
||||
config,
|
||||
&stream_in);
|
||||
#endif
|
||||
if (err < 0) {
|
||||
haltest_error("open output stream returned %d\n", err);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
buffer_size_in = stream_in->common.get_buffer_size(&stream_in->common);
|
||||
if (buffer_size_in == 0)
|
||||
haltest_error("Invalid buffer size received!\n");
|
||||
else
|
||||
haltest_info("Using buffer size: %zu\n", buffer_size_in);
|
||||
failed:
|
||||
if (config)
|
||||
free(config);
|
||||
}
|
||||
|
||||
static void close_input_stream_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_in);
|
||||
|
||||
if (play_thread)
|
||||
stop_p(argc, argv);
|
||||
|
||||
if_audio_sco->close_input_stream(if_audio_sco, stream_in);
|
||||
|
||||
stream_in = NULL;
|
||||
buffer_size_in = 0;
|
||||
}
|
||||
|
||||
static void cleanup_p(int argc, const char **argv)
|
||||
{
|
||||
int err;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_STOPPED) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
close_output_stream_p(0, NULL);
|
||||
} else {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
}
|
||||
|
||||
err = audio_hw_device_close(if_audio_sco);
|
||||
if (err < 0) {
|
||||
haltest_error("audio_hw_device_close returned %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if_audio_sco = NULL;
|
||||
}
|
||||
|
||||
static void suspend_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state != STATE_PLAYING) {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return;
|
||||
}
|
||||
current_state = STATE_SUSPENDED;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
|
||||
pthread_mutex_lock(&outstream_mutex);
|
||||
stream_out->common.standby(&stream_out->common);
|
||||
pthread_mutex_unlock(&outstream_mutex);
|
||||
}
|
||||
|
||||
static void resume_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
if (current_state == STATE_SUSPENDED)
|
||||
current_state = STATE_PLAYING;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
}
|
||||
|
||||
static void get_latency_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Output audio stream latency: %d\n",
|
||||
stream_out->get_latency(stream_out));
|
||||
}
|
||||
|
||||
static void get_buffer_size_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Current output buffer size: %zu\n",
|
||||
stream_out->common.get_buffer_size(&stream_out->common));
|
||||
}
|
||||
|
||||
static void get_channels_p(int argc, const char **argv)
|
||||
{
|
||||
audio_channel_mask_t channels;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
channels = stream_out->common.get_channels(&stream_out->common);
|
||||
|
||||
haltest_info("Channels: %s\n", audio_channel_mask_t2str(channels));
|
||||
}
|
||||
|
||||
static void get_format_p(int argc, const char **argv)
|
||||
{
|
||||
audio_format_t format;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
format = stream_out->common.get_format(&stream_out->common);
|
||||
|
||||
haltest_info("Format: %s\n", audio_format_t2str(format));
|
||||
}
|
||||
|
||||
static void get_sample_rate_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
haltest_info("Current sample rate: %d\n",
|
||||
stream_out->common.get_sample_rate(&stream_out->common));
|
||||
}
|
||||
|
||||
static void get_parameters_p(int argc, const char **argv)
|
||||
{
|
||||
const char *keystr;
|
||||
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_info("No keys given.\n");
|
||||
keystr = "";
|
||||
} else {
|
||||
keystr = argv[2];
|
||||
}
|
||||
|
||||
haltest_info("Current parameters: %s\n",
|
||||
stream_out->common.get_parameters(&stream_out->common,
|
||||
keystr));
|
||||
}
|
||||
|
||||
static void set_parameters_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3) {
|
||||
haltest_error("No key=value; pairs given.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
stream_out->common.set_parameters(&stream_out->common, argv[2]);
|
||||
}
|
||||
|
||||
static void set_sample_rate_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
RETURN_IF_NULL(stream_out);
|
||||
|
||||
if (argc < 3)
|
||||
return;
|
||||
|
||||
stream_out->common.set_sample_rate(&stream_out->common, atoi(argv[2]));
|
||||
}
|
||||
|
||||
static void init_check_p(int argc, const char **argv)
|
||||
{
|
||||
RETURN_IF_NULL(if_audio_sco);
|
||||
|
||||
haltest_info("Init check result: %d\n",
|
||||
if_audio_sco->init_check(if_audio_sco));
|
||||
}
|
||||
|
||||
static struct method methods[] = {
|
||||
STD_METHOD(init),
|
||||
STD_METHOD(cleanup),
|
||||
STD_METHODH(open_output_stream, "sample_rate"),
|
||||
STD_METHOD(close_output_stream),
|
||||
STD_METHODH(open_input_stream, "sampling rate"),
|
||||
STD_METHOD(close_input_stream),
|
||||
STD_METHODH(play, "<path to pcm file>"),
|
||||
STD_METHOD(read),
|
||||
STD_METHOD(loop),
|
||||
STD_METHOD(stop),
|
||||
STD_METHOD(suspend),
|
||||
STD_METHOD(resume),
|
||||
STD_METHOD(get_latency),
|
||||
STD_METHOD(get_buffer_size),
|
||||
STD_METHOD(get_channels),
|
||||
STD_METHOD(get_format),
|
||||
STD_METHOD(get_sample_rate),
|
||||
STD_METHODH(get_parameters, "<closing>"),
|
||||
STD_METHODH(set_parameters, "<closing=value>"),
|
||||
STD_METHODH(set_sample_rate, "<sample rate>"),
|
||||
STD_METHOD(init_check),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface sco_if = {
|
||||
.name = "sco",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,340 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "if-main.h"
|
||||
#include "pollhandler.h"
|
||||
#include "../hal-utils.h"
|
||||
|
||||
const btsock_interface_t *if_sock = NULL;
|
||||
|
||||
SINTMAP(btsock_type_t, -1, "(unknown)")
|
||||
DELEMENT(BTSOCK_RFCOMM),
|
||||
DELEMENT(BTSOCK_SCO),
|
||||
DELEMENT(BTSOCK_L2CAP),
|
||||
ENDMAP
|
||||
|
||||
#define MAX_LISTEN_FD 15
|
||||
static int listen_fd[MAX_LISTEN_FD];
|
||||
static int listen_fd_count;
|
||||
|
||||
static const char * const uuids[] = {
|
||||
"00001101", "00001105", "0000112f", NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* This function reads data from file descriptor and
|
||||
* prints it to the user
|
||||
*/
|
||||
static void receive_from_client(struct pollfd *pollfd)
|
||||
{
|
||||
char buf[16];
|
||||
/*
|
||||
* Buffer for lines:
|
||||
* 41 42 43 20 20 00 31 32 00 07 04 00 00 00 00 00 ABC .12.....
|
||||
*/
|
||||
char outbuf[sizeof(buf) * 4 + 2];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (pollfd->revents & POLLHUP) {
|
||||
haltest_error("Disconnected fd=%d\n", pollfd->fd);
|
||||
poll_unregister_fd(pollfd->fd, receive_from_client);
|
||||
} else if (pollfd->revents & POLLIN) {
|
||||
haltest_info("receiving from client fd=%d\n", pollfd->fd);
|
||||
|
||||
do {
|
||||
memset(outbuf, ' ', sizeof(outbuf));
|
||||
outbuf[sizeof(outbuf) - 1] = 0;
|
||||
ret = recv(pollfd->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
|
||||
for (i = 0; i < ret; ++i)
|
||||
sprintf(outbuf + i * 3, "%02X ",
|
||||
(unsigned) buf[i]);
|
||||
outbuf[i * 3] = ' ';
|
||||
for (i = 0; i < ret; ++i)
|
||||
sprintf(outbuf + 48 + i, "%c",
|
||||
(isprint(buf[i]) ? buf[i] : '.'));
|
||||
if (ret > 0)
|
||||
haltest_info("%s\n", outbuf);
|
||||
} while (ret > 0);
|
||||
} else {
|
||||
/* For now disconnect on all other events */
|
||||
haltest_error("Poll event %x\n", pollfd->revents);
|
||||
poll_unregister_fd(pollfd->fd, receive_from_client);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function read from fd socket information about
|
||||
* connected socket
|
||||
*/
|
||||
static void receive_sock_connect_signal(struct pollfd *pollfd)
|
||||
{
|
||||
sock_connect_signal_t cs;
|
||||
char addr_str[MAX_ADDR_STR_LEN];
|
||||
|
||||
if (pollfd->revents & POLLIN) {
|
||||
int ret;
|
||||
|
||||
poll_unregister_fd(pollfd->fd, receive_sock_connect_signal);
|
||||
ret = read(pollfd->fd, &cs, sizeof(cs));
|
||||
if (ret != sizeof(cs)) {
|
||||
haltest_info("Read on connect return %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
haltest_info("Connection to %s channel %d status=%d\n",
|
||||
bt_bdaddr_t2str(&cs.bd_addr, addr_str),
|
||||
cs.channel, cs.status);
|
||||
|
||||
if (cs.status == 0)
|
||||
poll_register_fd(pollfd->fd, POLLIN,
|
||||
receive_from_client);
|
||||
}
|
||||
|
||||
if (pollfd->revents & POLLHUP) {
|
||||
haltest_error("Disconnected fd=%d revents=0x%X\n", pollfd->fd,
|
||||
pollfd->revents);
|
||||
poll_unregister_fd(pollfd->fd, receive_sock_connect_signal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function read from fd socket information about
|
||||
* incoming connection and starts monitoring new connection
|
||||
* on file descriptor read from fd.
|
||||
*/
|
||||
static void read_accepted(int fd)
|
||||
{
|
||||
int ret;
|
||||
struct msghdr msg;
|
||||
struct iovec iv;
|
||||
char cmsgbuf[CMSG_SPACE(1)];
|
||||
struct cmsghdr *cmsgptr;
|
||||
sock_connect_signal_t cs;
|
||||
int accepted_fd = -1;
|
||||
char addr_str[MAX_ADDR_STR_LEN];
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&iv, 0, sizeof(iv));
|
||||
memset(cmsgbuf, 0, sizeof(cmsgbuf));
|
||||
|
||||
iv.iov_base = &cs;
|
||||
iv.iov_len = sizeof(cs);
|
||||
|
||||
msg.msg_iov = &iv;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
|
||||
do {
|
||||
ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 16 ||
|
||||
(msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0)
|
||||
haltest_error("Failed to accept connection\n");
|
||||
|
||||
for (cmsgptr = CMSG_FIRSTHDR(&msg);
|
||||
cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
|
||||
int count;
|
||||
|
||||
if (cmsgptr->cmsg_level != SOL_SOCKET ||
|
||||
cmsgptr->cmsg_type != SCM_RIGHTS)
|
||||
continue;
|
||||
|
||||
memcpy(&accepted_fd, CMSG_DATA(cmsgptr), sizeof(accepted_fd));
|
||||
count = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
||||
|
||||
if (count != 1)
|
||||
haltest_error("Failed to accept descriptors count=%d\n",
|
||||
count);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
haltest_info("Incoming connection from %s channel %d status=%d fd=%d\n",
|
||||
bt_bdaddr_t2str(&cs.bd_addr, addr_str),
|
||||
cs.channel, cs.status, accepted_fd);
|
||||
poll_register_fd(accepted_fd, POLLIN, receive_from_client);
|
||||
}
|
||||
|
||||
/* handles incoming connections on socket */
|
||||
static void client_connected(struct pollfd *pollfd)
|
||||
{
|
||||
haltest_info("client connected %x\n", pollfd->revents);
|
||||
|
||||
if (pollfd->revents & POLLHUP)
|
||||
poll_unregister_fd(pollfd->fd, client_connected);
|
||||
else if (pollfd->revents & POLLIN)
|
||||
read_accepted(pollfd->fd);
|
||||
}
|
||||
|
||||
/* listen */
|
||||
|
||||
static void listen_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*user = TYPE_ENUM(btsock_type_t);
|
||||
*enum_func = enum_defines;
|
||||
} else if (argc == 5) {
|
||||
*user = (void *) uuids;
|
||||
*enum_func = enum_strings;
|
||||
}
|
||||
}
|
||||
|
||||
static void listen_p(int argc, const char **argv)
|
||||
{
|
||||
btsock_type_t type;
|
||||
const char *service_name;
|
||||
bt_uuid_t service_uuid;
|
||||
int channel;
|
||||
int sock_fd = -1;
|
||||
int flags;
|
||||
|
||||
RETURN_IF_NULL(if_sock);
|
||||
|
||||
/* Socket type */
|
||||
if (argc < 3) {
|
||||
haltest_error("No socket type specified\n");
|
||||
return;
|
||||
}
|
||||
type = str2btsock_type_t(argv[2]);
|
||||
if ((int) type == -1)
|
||||
type = atoi(argv[2]);
|
||||
|
||||
/* service name */
|
||||
if (argc < 4) {
|
||||
haltest_error("No service name specified\n");
|
||||
return;
|
||||
}
|
||||
service_name = argv[3];
|
||||
|
||||
/* uuid */
|
||||
if (argc < 5) {
|
||||
haltest_error("No uuid specified\n");
|
||||
return;
|
||||
}
|
||||
str2bt_uuid_t(argv[4], &service_uuid);
|
||||
|
||||
/* channel */
|
||||
channel = argc > 5 ? atoi(argv[5]) : 0;
|
||||
|
||||
/* flags */
|
||||
flags = argc > 6 ? atoi(argv[6]) : 0;
|
||||
|
||||
if (listen_fd_count >= MAX_LISTEN_FD) {
|
||||
haltest_error("Max (%d) listening sockets exceeded\n",
|
||||
listen_fd_count);
|
||||
return;
|
||||
}
|
||||
EXEC(if_sock->listen, type, service_name,
|
||||
&service_uuid.uu[0], channel, &sock_fd, flags);
|
||||
if (sock_fd > 0) {
|
||||
int channel = 0;
|
||||
int ret = read(sock_fd, &channel, 4);
|
||||
if (ret != 4)
|
||||
haltest_info("Read channel failed\n");
|
||||
haltest_info("Channel returned from first read %d\n", channel);
|
||||
listen_fd[listen_fd_count++] = sock_fd;
|
||||
poll_register_fd(sock_fd, POLLIN, client_connected);
|
||||
}
|
||||
}
|
||||
|
||||
/* connect */
|
||||
|
||||
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
||||
void **user)
|
||||
{
|
||||
if (argc == 3) {
|
||||
*enum_func = enum_devices;
|
||||
} else if (argc == 4) {
|
||||
*user = TYPE_ENUM(btsock_type_t);
|
||||
*enum_func = enum_defines;
|
||||
} else if (argc == 5) {
|
||||
*user = (void *) uuids;
|
||||
*enum_func = enum_strings;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_p(int argc, const char **argv)
|
||||
{
|
||||
bt_bdaddr_t addr;
|
||||
btsock_type_t type;
|
||||
bt_uuid_t uuid;
|
||||
int channel;
|
||||
int sock_fd = -1;
|
||||
int flags;
|
||||
|
||||
/* Address */
|
||||
if (argc <= 2) {
|
||||
haltest_error("No address specified\n");
|
||||
return;
|
||||
}
|
||||
str2bt_bdaddr_t(argv[2], &addr);
|
||||
|
||||
/* Socket type */
|
||||
if (argc <= 3) {
|
||||
haltest_error("No socket type specified\n");
|
||||
return;
|
||||
}
|
||||
type = str2btsock_type_t(argv[3]);
|
||||
if ((int) type == -1)
|
||||
type = atoi(argv[3]);
|
||||
|
||||
/* uuid */
|
||||
if (argc <= 4) {
|
||||
haltest_error("No uuid specified\n");
|
||||
return;
|
||||
}
|
||||
str2bt_uuid_t(argv[4], &uuid);
|
||||
|
||||
/* channel */
|
||||
if (argc <= 5) {
|
||||
haltest_error("No channel specified\n");
|
||||
return;
|
||||
}
|
||||
channel = atoi(argv[5]);
|
||||
|
||||
/* flags */
|
||||
flags = argc <= 6 ? 0 : atoi(argv[6]);
|
||||
|
||||
RETURN_IF_NULL(if_sock);
|
||||
|
||||
EXEC(if_sock->connect, &addr, type, &uuid.uu[0], channel, &sock_fd,
|
||||
flags);
|
||||
if (sock_fd > 0) {
|
||||
int channel = 0;
|
||||
int ret = read(sock_fd, &channel, 4);
|
||||
|
||||
if (ret != 4)
|
||||
haltest_info("Read channel failed\n");
|
||||
haltest_info("Channel returned from first read %d\n", channel);
|
||||
listen_fd[listen_fd_count++] = sock_fd;
|
||||
poll_register_fd(sock_fd, POLLIN, receive_sock_connect_signal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Methods available in btsock_interface_t */
|
||||
static struct method methods[] = {
|
||||
STD_METHODCH(listen,
|
||||
"<sock_type> <srvc_name> <uuid> [<channel>] [<flags>]"),
|
||||
STD_METHODCH(connect,
|
||||
"<addr> <sock_type> <uuid> <channel> [<flags>]"),
|
||||
END_METHOD
|
||||
};
|
||||
|
||||
const struct interface sock_if = {
|
||||
.name = "socket",
|
||||
.methods = methods
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "pollhandler.h"
|
||||
|
||||
/*
|
||||
* Code that allows to poll multiply file descriptors for events
|
||||
* File descriptors can be added and removed at runtime
|
||||
*
|
||||
* Call poll_register_fd function first to add file descriptors to monitor
|
||||
* Then call poll_dispatch_loop that will poll all registered file descriptors
|
||||
* as long as they are not unregistered.
|
||||
*
|
||||
* When event happen on given fd appropriate user supplied handler is called
|
||||
*/
|
||||
|
||||
/* Maximum number of files to monitor */
|
||||
#define MAX_OPEN_FD 10
|
||||
|
||||
/* Storage for pollfd structures for monitored file descriptors */
|
||||
static struct pollfd fds[MAX_OPEN_FD];
|
||||
static poll_handler fds_handler[MAX_OPEN_FD];
|
||||
/* Number of registered file descriptors */
|
||||
static int fds_count = 0;
|
||||
|
||||
/*
|
||||
* Function polls file descriptor in loop and calls appropriate handler
|
||||
* on event. Function returns when there is no more file descriptor to
|
||||
* monitor
|
||||
*/
|
||||
void poll_dispatch_loop(void)
|
||||
{
|
||||
while (fds_count > 0) {
|
||||
int i;
|
||||
int cur_fds_count = fds_count;
|
||||
int ready = poll(fds, fds_count, 1000);
|
||||
|
||||
for (i = 0; i < fds_count && ready > 0; ++i) {
|
||||
if (fds[i].revents == 0)
|
||||
continue;
|
||||
|
||||
fds_handler[i](fds + i);
|
||||
ready--;
|
||||
/*
|
||||
* If handler was remove from table
|
||||
* just skip the rest and poll again
|
||||
* This is due to reordering of tables in
|
||||
* register/unregister functions
|
||||
*/
|
||||
if (cur_fds_count != fds_count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Registers file descriptor to be monitored for events (see man poll(2))
|
||||
* for events.
|
||||
*
|
||||
* return non negative value on success
|
||||
* -EMFILE when there are to much descriptors
|
||||
*/
|
||||
int poll_register_fd(int fd, short events, poll_handler ph)
|
||||
{
|
||||
if (fds_count >= MAX_OPEN_FD)
|
||||
return -EMFILE;
|
||||
|
||||
fds_handler[fds_count] = ph;
|
||||
fds[fds_count].fd = fd;
|
||||
fds[fds_count].events = events;
|
||||
fds_count++;
|
||||
|
||||
return fds_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregisters file descriptor
|
||||
* Both fd and ph must match previously registered data
|
||||
*
|
||||
* return 0 if unregister succeeded
|
||||
* -EBADF if arguments do not match any register handler
|
||||
*/
|
||||
int poll_unregister_fd(int fd, poll_handler ph)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fds_count; ++i) {
|
||||
if (fds_handler[i] == ph && fds[i].fd == fd) {
|
||||
fds_count--;
|
||||
if (i < fds_count) {
|
||||
fds[i].fd = fds[fds_count].fd;
|
||||
fds[i].events = fds[fds_count].events;
|
||||
fds_handler[i] = fds_handler[fds_count];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EBADF;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
/* Function to be called when there are event for some descriptor */
|
||||
typedef void (*poll_handler)(struct pollfd *pollfd);
|
||||
|
||||
int poll_register_fd(int fd, short events, poll_handler ph);
|
||||
int poll_unregister_fd(int fd, poll_handler ph);
|
||||
|
||||
void poll_dispatch_loop(void);
|
||||
@@ -0,0 +1,364 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "if-main.h"
|
||||
#include "terminal.h"
|
||||
|
||||
/* how many times tab was hit */
|
||||
static int tab_hit_count;
|
||||
|
||||
typedef struct split_arg {
|
||||
struct split_arg *next; /* next argument in buffer */
|
||||
const char *origin; /* pointer to original argument */
|
||||
char ntcopy[1]; /* null terminated copy of argument */
|
||||
} split_arg_t;
|
||||
|
||||
/* function returns method of given name or NULL if not found */
|
||||
const struct method *get_interface_method(const char *iname,
|
||||
const char *mname)
|
||||
{
|
||||
const struct interface *iface = get_interface(iname);
|
||||
|
||||
if (iface == NULL)
|
||||
return NULL;
|
||||
|
||||
return get_method(iface->methods, mname);
|
||||
}
|
||||
|
||||
/* prints matching elements */
|
||||
static void print_matches(enum_func f, void *user, const char *prefix, int len)
|
||||
{
|
||||
int i;
|
||||
const char *enum_name;
|
||||
|
||||
putchar('\n');
|
||||
for (i = 0; NULL != (enum_name = f(user, i)); ++i) {
|
||||
if (strncmp(enum_name, prefix, len) == 0)
|
||||
printf("%s\t", enum_name);
|
||||
}
|
||||
putchar('\n');
|
||||
terminal_draw_command_line();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function splits command line into linked list of arguments.
|
||||
* line_buffer - pointer to input command line
|
||||
* size - size of command line to parse
|
||||
* buf - output buffer to keep split arguments list
|
||||
* buf_size_in_bytes - size of buf
|
||||
*/
|
||||
static int split_command(const char *line_buffer, int size, split_arg_t *buf,
|
||||
int buf_size_in_bytes)
|
||||
{
|
||||
split_arg_t *prev = NULL;
|
||||
split_arg_t *arg = buf;
|
||||
int argc = 0;
|
||||
const char *p = line_buffer;
|
||||
const char *e = p + (size > 0 ? size : (int) strlen(p));
|
||||
int len;
|
||||
|
||||
do {
|
||||
while (p < e && isspace(*p))
|
||||
p++;
|
||||
arg->origin = p;
|
||||
arg->next = NULL;
|
||||
while (p < e && !isspace(*p))
|
||||
p++;
|
||||
len = p - arg->origin;
|
||||
if (&arg->ntcopy[0] + len + 1 >
|
||||
(const char *) buf + buf_size_in_bytes)
|
||||
break;
|
||||
strncpy(arg->ntcopy, arg->origin, len);
|
||||
arg->ntcopy[len] = 0;
|
||||
if (prev != NULL)
|
||||
prev->next = arg;
|
||||
prev = arg;
|
||||
arg += (2 * sizeof(*arg) + len) / sizeof(*arg);
|
||||
argc++;
|
||||
} while (p < e);
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
/* Function to enumerate method names */
|
||||
static const char *methods_name(void *v, int i)
|
||||
{
|
||||
const struct interface *iface = v;
|
||||
|
||||
return iface->methods[i].name[0] ? iface->methods[i].name : NULL;
|
||||
}
|
||||
|
||||
struct command_completion_args;
|
||||
typedef void (*short_help)(struct command_completion_args *args);
|
||||
|
||||
struct command_completion_args {
|
||||
const split_arg_t *arg; /* list of arguments */
|
||||
const char *typed; /* last typed element */
|
||||
enum_func func; /* enumerating function */
|
||||
void *user; /* argument to enumerating function */
|
||||
short_help help; /* help function */
|
||||
const char *user_help; /* additional data (used by short_help) */
|
||||
};
|
||||
|
||||
/* complete command line */
|
||||
static void tab_completion(struct command_completion_args *args)
|
||||
{
|
||||
const char *name = args->typed;
|
||||
const int len = strlen(name);
|
||||
int i;
|
||||
int j;
|
||||
char prefix[128] = {0};
|
||||
int prefix_len = 0;
|
||||
int count = 0;
|
||||
const char *enum_name;
|
||||
|
||||
for (i = 0; NULL != (enum_name = args->func(args->user, i)); ++i) {
|
||||
/* prefix does not match */
|
||||
if (strncmp(enum_name, name, len) != 0)
|
||||
continue;
|
||||
|
||||
/* prefix matches first time */
|
||||
if (count++ == 0) {
|
||||
strcpy(prefix, enum_name);
|
||||
prefix_len = strlen(prefix);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Prefix matches next time reduce prefix to common part */
|
||||
for (j = 0; prefix[j] != 0
|
||||
&& prefix[j] == enum_name[j];)
|
||||
++j;
|
||||
prefix_len = j;
|
||||
prefix[j] = 0;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
/* no matches */
|
||||
if (args->help != NULL)
|
||||
args->help(args);
|
||||
tab_hit_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* len == prefix_len => nothing new was added */
|
||||
if (len == prefix_len) {
|
||||
if (count != 1) {
|
||||
if (tab_hit_count == 1) {
|
||||
putchar('\a');
|
||||
} else if (tab_hit_count == 2 ||
|
||||
args->help == NULL) {
|
||||
print_matches(args->func,
|
||||
args->user, name, len);
|
||||
} else {
|
||||
args->help(args);
|
||||
tab_hit_count = 1;
|
||||
}
|
||||
} else if (count == 1) {
|
||||
/* nothing to add, exact match add space */
|
||||
terminal_insert_into_command_line(" ");
|
||||
}
|
||||
} else {
|
||||
/* new chars can be added from some interface name(s) */
|
||||
if (count == 1) {
|
||||
/* exact match, add space */
|
||||
prefix[prefix_len++] = ' ';
|
||||
prefix[prefix_len] = '\0';
|
||||
}
|
||||
|
||||
terminal_insert_into_command_line(prefix + len);
|
||||
tab_hit_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* interface completion */
|
||||
static void command_completion(split_arg_t *arg)
|
||||
{
|
||||
struct command_completion_args args = {
|
||||
.arg = arg,
|
||||
.typed = arg->ntcopy,
|
||||
.func = command_name
|
||||
};
|
||||
|
||||
tab_completion(&args);
|
||||
}
|
||||
|
||||
/* method completion */
|
||||
static void method_completion(const struct interface *iface, split_arg_t *arg)
|
||||
{
|
||||
struct command_completion_args args = {
|
||||
.arg = arg,
|
||||
.typed = arg->next->ntcopy,
|
||||
.func = methods_name,
|
||||
.user = (void *) iface
|
||||
};
|
||||
|
||||
if (iface == NULL)
|
||||
return;
|
||||
|
||||
tab_completion(&args);
|
||||
}
|
||||
|
||||
static const char *bold = "\x1b[1m";
|
||||
static const char *normal = "\x1b[0m";
|
||||
|
||||
static bool find_nth_argument(const char *str, int n, const char **s,
|
||||
const char **e)
|
||||
{
|
||||
const char *p = str;
|
||||
int argc = 0;
|
||||
*e = NULL;
|
||||
|
||||
while (p != NULL && *p != 0) {
|
||||
|
||||
while (isspace(*p))
|
||||
++p;
|
||||
|
||||
if (n == argc)
|
||||
*s = p;
|
||||
|
||||
if (*p == '[') {
|
||||
p = strchr(p, ']');
|
||||
if (p != NULL)
|
||||
*e = ++p;
|
||||
} else if (*p == '<') {
|
||||
p = strchr(p, '>');
|
||||
if (p != NULL)
|
||||
*e = ++p;
|
||||
} else {
|
||||
*e = strchr(p, ' ');
|
||||
if (*e == NULL)
|
||||
*e = p + strlen(p);
|
||||
p = *e;
|
||||
}
|
||||
|
||||
if (n == argc)
|
||||
break;
|
||||
|
||||
argc++;
|
||||
*e = NULL;
|
||||
}
|
||||
return *e != NULL;
|
||||
}
|
||||
|
||||
/* prints short help on method for interface */
|
||||
static void method_help(struct command_completion_args *args)
|
||||
{
|
||||
int argc;
|
||||
const split_arg_t *arg = args->arg;
|
||||
const char *sb = NULL;
|
||||
const char *eb = NULL;
|
||||
const char *arg1 = "";
|
||||
int arg1_size = 0; /* size of method field (for methods > 0) */
|
||||
|
||||
if (args->user_help == NULL)
|
||||
return;
|
||||
|
||||
for (argc = 0; arg != NULL; argc++)
|
||||
arg = arg->next;
|
||||
|
||||
/* Check if this is method from interface */
|
||||
if (get_command(args->arg->ntcopy) == NULL) {
|
||||
/* if so help is missing interface and method name */
|
||||
arg1 = args->arg->next->ntcopy;
|
||||
arg1_size = strlen(arg1) + 1;
|
||||
}
|
||||
|
||||
find_nth_argument(args->user_help, argc - (arg1_size ? 3 : 2),
|
||||
&sb, &eb);
|
||||
|
||||
if (eb != NULL)
|
||||
haltest_info("%s %-*s%.*s%s%.*s%s%s\n", args->arg->ntcopy,
|
||||
arg1_size, arg1, (int) (sb - args->user_help),
|
||||
args->user_help, bold, (int) (eb - sb),
|
||||
sb, normal, eb);
|
||||
else
|
||||
haltest_info("%s %-*s%s\n", args->arg->ntcopy,
|
||||
arg1_size, arg1, args->user_help);
|
||||
}
|
||||
|
||||
/* So we have empty enumeration */
|
||||
static const char *return_null(void *user, int i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* parameter completion function
|
||||
* argc - number of elements in arg list
|
||||
* arg - list of arguments
|
||||
* method - method to get completion from (can be NULL)
|
||||
*/
|
||||
static void param_completion(int argc, const split_arg_t *arg,
|
||||
const struct method *method, int hlpix)
|
||||
{
|
||||
int i;
|
||||
const char *argv[argc];
|
||||
const split_arg_t *tmp = arg;
|
||||
struct command_completion_args args = {
|
||||
.arg = arg,
|
||||
.func = return_null
|
||||
};
|
||||
|
||||
/* prepare standard argv from arg */
|
||||
for (i = 0; i < argc; ++i) {
|
||||
argv[i] = tmp->ntcopy;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (method != NULL && method->complete != NULL) {
|
||||
/* ask method for completion function */
|
||||
method->complete(argc, argv, &args.func, &args.user);
|
||||
}
|
||||
|
||||
/* If method provided enumeration function call try to complete */
|
||||
if (args.func != NULL) {
|
||||
args.typed = argv[argc - 1];
|
||||
args.help = method_help;
|
||||
args.user_help = method ? method->help : NULL;
|
||||
|
||||
tab_completion(&args);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method gets called when user tapped tab key.
|
||||
* line - points to command line
|
||||
* len - size of line that should be used for completions. This should be
|
||||
* cursor position during tab hit.
|
||||
*/
|
||||
void process_tab(const char *line, int len)
|
||||
{
|
||||
int argc;
|
||||
static split_arg_t buf[(LINE_BUF_MAX * 2) / sizeof(split_arg_t)];
|
||||
const struct method *method;
|
||||
|
||||
argc = split_command(line, len, buf, sizeof(buf));
|
||||
tab_hit_count++;
|
||||
|
||||
if (argc == 0)
|
||||
return;
|
||||
|
||||
if (argc == 1) {
|
||||
command_completion(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
method = get_command(buf[0].ntcopy);
|
||||
if (method != NULL) {
|
||||
param_completion(argc, buf, method, 1);
|
||||
} else if (argc == 2) {
|
||||
method_completion(get_interface(buf[0].ntcopy), buf);
|
||||
} else {
|
||||
/* Find method for <interface, name> pair */
|
||||
method = get_interface_method(buf[0].ntcopy,
|
||||
buf[0].next->ntcopy);
|
||||
param_completion(argc, buf, method, 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,813 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <termios.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include "history.h"
|
||||
|
||||
/*
|
||||
* Character sequences recognized by code in this file
|
||||
* Leading ESC 0x1B is not included
|
||||
*/
|
||||
#define SEQ_INSERT "[2~"
|
||||
#define SEQ_DELETE "[3~"
|
||||
#define SEQ_HOME "OH"
|
||||
#define SEQ_END "OF"
|
||||
#define SEQ_PGUP "[5~"
|
||||
#define SEQ_PGDOWN "[6~"
|
||||
#define SEQ_LEFT "[D"
|
||||
#define SEQ_RIGHT "[C"
|
||||
#define SEQ_UP "[A"
|
||||
#define SEQ_DOWN "[B"
|
||||
#define SEQ_STAB "[Z"
|
||||
#define SEQ_M_n "n"
|
||||
#define SEQ_M_p "p"
|
||||
#define SEQ_CLEFT "[1;5D"
|
||||
#define SEQ_CRIGHT "[1;5C"
|
||||
#define SEQ_CUP "[1;5A"
|
||||
#define SEQ_CDOWN "[1;5B"
|
||||
#define SEQ_SLEFT "[1;2D"
|
||||
#define SEQ_SRIGHT "[1;2C"
|
||||
#define SEQ_SUP "[1;2A"
|
||||
#define SEQ_SDOWN "[1;2B"
|
||||
#define SEQ_MLEFT "[1;3D"
|
||||
#define SEQ_MRIGHT "[1;3C"
|
||||
#define SEQ_MUP "[1;3A"
|
||||
#define SEQ_MDOWN "[1;3B"
|
||||
|
||||
#define KEY_SEQUENCE(k) { KEY_##k, SEQ_##k }
|
||||
struct ansii_sequence {
|
||||
int code;
|
||||
const char *sequence;
|
||||
};
|
||||
|
||||
/* Table connects single int key codes with character sequences */
|
||||
static const struct ansii_sequence ansii_sequnces[] = {
|
||||
KEY_SEQUENCE(INSERT),
|
||||
KEY_SEQUENCE(DELETE),
|
||||
KEY_SEQUENCE(HOME),
|
||||
KEY_SEQUENCE(END),
|
||||
KEY_SEQUENCE(PGUP),
|
||||
KEY_SEQUENCE(PGDOWN),
|
||||
KEY_SEQUENCE(LEFT),
|
||||
KEY_SEQUENCE(RIGHT),
|
||||
KEY_SEQUENCE(UP),
|
||||
KEY_SEQUENCE(DOWN),
|
||||
KEY_SEQUENCE(CLEFT),
|
||||
KEY_SEQUENCE(CRIGHT),
|
||||
KEY_SEQUENCE(CUP),
|
||||
KEY_SEQUENCE(CDOWN),
|
||||
KEY_SEQUENCE(SLEFT),
|
||||
KEY_SEQUENCE(SRIGHT),
|
||||
KEY_SEQUENCE(SUP),
|
||||
KEY_SEQUENCE(SDOWN),
|
||||
KEY_SEQUENCE(MLEFT),
|
||||
KEY_SEQUENCE(MRIGHT),
|
||||
KEY_SEQUENCE(MUP),
|
||||
KEY_SEQUENCE(MDOWN),
|
||||
KEY_SEQUENCE(STAB),
|
||||
KEY_SEQUENCE(M_p),
|
||||
KEY_SEQUENCE(M_n),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#define KEY_SEQUNCE_NOT_FINISHED -1
|
||||
#define KEY_C_C 3
|
||||
#define KEY_C_D 4
|
||||
#define KEY_C_L 12
|
||||
|
||||
#define isseqence(c) ((c) == 0x1B)
|
||||
|
||||
/*
|
||||
* Number of characters that consist of ANSI sequence
|
||||
* Should not be less then longest string in ansi_sequences
|
||||
*/
|
||||
#define MAX_ASCII_SEQUENCE 10
|
||||
|
||||
static char current_sequence[MAX_ASCII_SEQUENCE];
|
||||
static int current_sequence_len = -1;
|
||||
|
||||
/* single line typed by user goes here */
|
||||
static char line_buf[LINE_BUF_MAX];
|
||||
/* index of cursor in input line */
|
||||
static int line_buf_ix = 0;
|
||||
/* current length of input line */
|
||||
static int line_len = 0;
|
||||
|
||||
/* line index used for fetching lines from history */
|
||||
static int line_index = 0;
|
||||
|
||||
static char prompt_buf[10] = "> ";
|
||||
static const char *const noprompt = "";
|
||||
static const char *current_prompt = prompt_buf;
|
||||
static const char *prompt = prompt_buf;
|
||||
/*
|
||||
* Moves cursor to right or left
|
||||
*
|
||||
* n - positive - moves cursor right
|
||||
* n - negative - moves cursor left
|
||||
*/
|
||||
static void terminal_move_cursor(int n)
|
||||
{
|
||||
if (n < 0) {
|
||||
for (; n < 0; n++)
|
||||
putchar('\b');
|
||||
} else if (n > 0) {
|
||||
printf("%*s", n, line_buf + line_buf_ix);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw command line */
|
||||
void terminal_draw_command_line(void)
|
||||
{
|
||||
/*
|
||||
* this needs to be checked here since line_buf is not cleared
|
||||
* before parsing event though line_len and line_buf_ix are
|
||||
*/
|
||||
if (line_len > 0)
|
||||
printf("%s%s", prompt, line_buf);
|
||||
else
|
||||
printf("%s", prompt);
|
||||
|
||||
/* move cursor to it's place */
|
||||
terminal_move_cursor(line_buf_ix - line_len);
|
||||
}
|
||||
|
||||
/* inserts string into command line at cursor position */
|
||||
void terminal_insert_into_command_line(const char *p)
|
||||
{
|
||||
int len = strlen(p);
|
||||
|
||||
if (line_len == line_buf_ix) {
|
||||
strcat(line_buf, p);
|
||||
printf("%s", p);
|
||||
line_len = line_len + len;
|
||||
line_buf_ix = line_len;
|
||||
} else {
|
||||
memmove(line_buf + line_buf_ix + len,
|
||||
line_buf + line_buf_ix, line_len - line_buf_ix + 1);
|
||||
memmove(line_buf + line_buf_ix, p, len);
|
||||
printf("%s", line_buf + line_buf_ix);
|
||||
line_buf_ix += len;
|
||||
line_len += len;
|
||||
terminal_move_cursor(line_buf_ix - line_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prints string and redraws command line */
|
||||
int terminal_print(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
ret = terminal_vprint(format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Prints string and redraws command line */
|
||||
int terminal_vprint(const char *format, va_list args)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printf("\r%*s\r", (int) line_len + 1, " ");
|
||||
|
||||
ret = vprintf(format, args);
|
||||
|
||||
terminal_draw_command_line();
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this when text in line_buf was changed
|
||||
* and line needs to be redrawn
|
||||
*/
|
||||
static void terminal_line_replaced(void)
|
||||
{
|
||||
int len = strlen(line_buf);
|
||||
|
||||
/* line is shorter that previous */
|
||||
if (len < line_len) {
|
||||
/* if new line is shorter move cursor to end of new end */
|
||||
while (line_buf_ix > len) {
|
||||
putchar('\b');
|
||||
line_buf_ix--;
|
||||
}
|
||||
|
||||
/* If cursor was not at the end, move it to the end */
|
||||
if (line_buf_ix < line_len)
|
||||
printf("%.*s", line_len - line_buf_ix,
|
||||
line_buf + line_buf_ix);
|
||||
/* over write end of previous line */
|
||||
while (line_len >= len++)
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
/* draw new line */
|
||||
printf("\r%s%s", prompt, line_buf);
|
||||
/* set up indexes to new line */
|
||||
line_len = strlen(line_buf);
|
||||
line_buf_ix = line_len;
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void terminal_clear_line(void)
|
||||
{
|
||||
line_buf[0] = '\0';
|
||||
terminal_line_replaced();
|
||||
}
|
||||
|
||||
static void terminal_clear_screen(void)
|
||||
{
|
||||
line_buf[0] = '\0';
|
||||
line_buf_ix = 0;
|
||||
line_len = 0;
|
||||
|
||||
printf("\x1b[2J\x1b[1;1H%s", prompt);
|
||||
}
|
||||
|
||||
static void terminal_delete_char(void)
|
||||
{
|
||||
/* delete character under cursor if not at the very end */
|
||||
if (line_buf_ix >= line_len)
|
||||
return;
|
||||
/*
|
||||
* Prepare buffer with one character missing
|
||||
* trailing 0 is moved
|
||||
*/
|
||||
line_len--;
|
||||
memmove(line_buf + line_buf_ix, line_buf + line_buf_ix + 1,
|
||||
line_len - line_buf_ix + 1);
|
||||
/* print rest of line from current cursor position */
|
||||
printf("%s \b", line_buf + line_buf_ix);
|
||||
/* move back cursor */
|
||||
terminal_move_cursor(line_buf_ix - line_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function tries to replace current line with specified line in history
|
||||
* new_line_index - new line to show, -1 to show oldest
|
||||
*/
|
||||
static void terminal_get_line_from_history(int new_line_index)
|
||||
{
|
||||
new_line_index = history_get_line(new_line_index,
|
||||
line_buf, LINE_BUF_MAX);
|
||||
|
||||
if (new_line_index >= 0) {
|
||||
terminal_line_replaced();
|
||||
line_index = new_line_index;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function searches history back or forward for command line that starts
|
||||
* with characters up to cursor position
|
||||
*
|
||||
* back - true - searches backward
|
||||
* back - false - searches forward (more recent commands)
|
||||
*/
|
||||
static void terminal_match_hitory(bool back)
|
||||
{
|
||||
char buf[line_buf_ix + 1];
|
||||
int line;
|
||||
int matching_line = -1;
|
||||
int dir = back ? 1 : -1;
|
||||
|
||||
line = line_index + dir;
|
||||
while (matching_line == -1 && line >= 0) {
|
||||
int new_line_index;
|
||||
|
||||
new_line_index = history_get_line(line, buf, line_buf_ix + 1);
|
||||
if (new_line_index < 0)
|
||||
break;
|
||||
|
||||
if (0 == strncmp(line_buf, buf, line_buf_ix))
|
||||
matching_line = line;
|
||||
line += dir;
|
||||
}
|
||||
|
||||
if (matching_line >= 0) {
|
||||
int pos = line_buf_ix;
|
||||
terminal_get_line_from_history(matching_line);
|
||||
/* move back to cursor position to original place */
|
||||
line_buf_ix = pos;
|
||||
terminal_move_cursor(pos - line_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts terminal character sequences to single value representing
|
||||
* keyboard keys
|
||||
*/
|
||||
static int terminal_convert_sequence(int c)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Not in sequence yet? */
|
||||
if (current_sequence_len == -1) {
|
||||
/* Is ansi sequence detected by 0x1B ? */
|
||||
if (isseqence(c)) {
|
||||
current_sequence_len++;
|
||||
return KEY_SEQUNCE_NOT_FINISHED;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Inside sequence */
|
||||
current_sequence[current_sequence_len++] = c;
|
||||
current_sequence[current_sequence_len] = '\0';
|
||||
for (i = 0; ansii_sequnces[i].code; ++i) {
|
||||
/* Matches so far? */
|
||||
if (0 != strncmp(current_sequence, ansii_sequnces[i].sequence,
|
||||
current_sequence_len))
|
||||
continue;
|
||||
|
||||
/* Matches as a whole? */
|
||||
if (ansii_sequnces[i].sequence[current_sequence_len] == 0) {
|
||||
current_sequence_len = -1;
|
||||
return ansii_sequnces[i].code;
|
||||
}
|
||||
|
||||
/* partial match (not whole sequence yet) */
|
||||
return KEY_SEQUNCE_NOT_FINISHED;
|
||||
}
|
||||
|
||||
terminal_print("ansi char 0x%X %c\n", c);
|
||||
/*
|
||||
* Sequence does not match
|
||||
* mark that no in sequence any more, return char
|
||||
*/
|
||||
current_sequence_len = -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
typedef void (*terminal_action)(int c, line_callback process_line);
|
||||
|
||||
#define TERMINAL_ACTION(n) \
|
||||
static void n(int c, void (*process_line)(char *line))
|
||||
|
||||
TERMINAL_ACTION(terminal_action_null)
|
||||
{
|
||||
}
|
||||
|
||||
/* Mapping between keys and function */
|
||||
typedef struct {
|
||||
int key;
|
||||
terminal_action func;
|
||||
} KeyAction;
|
||||
|
||||
int action_keys[] = {
|
||||
KEY_SEQUNCE_NOT_FINISHED,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_HOME,
|
||||
KEY_END,
|
||||
KEY_DELETE,
|
||||
KEY_CLEFT,
|
||||
KEY_CRIGHT,
|
||||
KEY_SUP,
|
||||
KEY_SDOWN,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_BACKSPACE,
|
||||
KEY_INSERT,
|
||||
KEY_PGUP,
|
||||
KEY_PGDOWN,
|
||||
KEY_CUP,
|
||||
KEY_CDOWN,
|
||||
KEY_SLEFT,
|
||||
KEY_SRIGHT,
|
||||
KEY_MLEFT,
|
||||
KEY_MRIGHT,
|
||||
KEY_MUP,
|
||||
KEY_MDOWN,
|
||||
KEY_STAB,
|
||||
KEY_M_n,
|
||||
KEY_M_p,
|
||||
KEY_C_C,
|
||||
KEY_C_D,
|
||||
KEY_C_L,
|
||||
'\t',
|
||||
'\r',
|
||||
'\n',
|
||||
};
|
||||
|
||||
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
||||
|
||||
/*
|
||||
* current_actions holds all recognizable kes and actions for them
|
||||
* additional element (index 0) is used for default action
|
||||
*/
|
||||
static KeyAction current_actions[NELEM(action_keys) + 1];
|
||||
|
||||
/* KeyAction comparator by key, for qsort and bsearch */
|
||||
static int KeyActionKeyCompare(const void *a, const void *b)
|
||||
{
|
||||
return ((const KeyAction *) a)->key - ((const KeyAction *) b)->key;
|
||||
}
|
||||
|
||||
/* Find action by key, NULL if no action for this key */
|
||||
static KeyAction *terminal_get_action(int key)
|
||||
{
|
||||
KeyAction a = { .key = key };
|
||||
|
||||
return bsearch(&a, current_actions + 1, NELEM(action_keys), sizeof(a),
|
||||
KeyActionKeyCompare);
|
||||
}
|
||||
|
||||
/* Sets new set of actions to use */
|
||||
static void terminal_set_actions(const KeyAction *actions)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Make map with empty function for every key */
|
||||
for (i = 0; i < NELEM(action_keys); ++i) {
|
||||
/*
|
||||
* + 1 due to 0 index reserved for default action that is
|
||||
* called for non mapped key
|
||||
*/
|
||||
current_actions[i + 1].key = action_keys[i];
|
||||
current_actions[i + 1].func = terminal_action_null;
|
||||
}
|
||||
|
||||
/* Sort action from 1 (index 0 - default action) */
|
||||
qsort(current_actions + 1, NELEM(action_keys), sizeof(KeyAction),
|
||||
KeyActionKeyCompare);
|
||||
/* Set default action (first in array) */
|
||||
current_actions[0] = *actions++;
|
||||
|
||||
/* Copy rest of actions into their places */
|
||||
for (; actions->key; ++actions) {
|
||||
KeyAction *place = terminal_get_action(actions->key);
|
||||
|
||||
if (place)
|
||||
place->func = actions->func;
|
||||
}
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_left)
|
||||
{
|
||||
/* if not at the beginning move to previous character */
|
||||
if (line_buf_ix <= 0)
|
||||
return;
|
||||
line_buf_ix--;
|
||||
terminal_move_cursor(-1);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_right)
|
||||
{
|
||||
/*
|
||||
* If not at the end, just print current character
|
||||
* and modify position
|
||||
*/
|
||||
if (line_buf_ix < line_len)
|
||||
putchar(line_buf[line_buf_ix++]);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_home)
|
||||
{
|
||||
/* move to beginning of line and update position */
|
||||
printf("\r%s", prompt);
|
||||
line_buf_ix = 0;
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_end)
|
||||
{
|
||||
/* if not at the end of line */
|
||||
if (line_buf_ix < line_len) {
|
||||
/* print everything from cursor */
|
||||
printf("%s", line_buf + line_buf_ix);
|
||||
/* just modify current position */
|
||||
line_buf_ix = line_len;
|
||||
}
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_del)
|
||||
{
|
||||
terminal_delete_char();
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_word_left)
|
||||
{
|
||||
int old_pos;
|
||||
/*
|
||||
* Move by word left
|
||||
*
|
||||
* Are we at the beginning of line?
|
||||
*/
|
||||
if (line_buf_ix <= 0)
|
||||
return;
|
||||
|
||||
old_pos = line_buf_ix;
|
||||
line_buf_ix--;
|
||||
/* skip spaces left */
|
||||
while (line_buf_ix && isspace(line_buf[line_buf_ix]))
|
||||
line_buf_ix--;
|
||||
|
||||
/* skip all non spaces to the left */
|
||||
while (line_buf_ix > 0 &&
|
||||
!isspace(line_buf[line_buf_ix - 1]))
|
||||
line_buf_ix--;
|
||||
|
||||
/* move cursor to new position */
|
||||
terminal_move_cursor(line_buf_ix - old_pos);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_word_right)
|
||||
{
|
||||
int old_pos;
|
||||
/*
|
||||
* Move by word right
|
||||
*
|
||||
* are we at the end of line?
|
||||
*/
|
||||
if (line_buf_ix >= line_len)
|
||||
return;
|
||||
|
||||
old_pos = line_buf_ix;
|
||||
/* skip all spaces */
|
||||
while (line_buf_ix < line_len && isspace(line_buf[line_buf_ix]))
|
||||
line_buf_ix++;
|
||||
|
||||
/* skip all non spaces */
|
||||
while (line_buf_ix < line_len && !isspace(line_buf[line_buf_ix]))
|
||||
line_buf_ix++;
|
||||
/*
|
||||
* Move cursor to right by printing text
|
||||
* between old cursor and new
|
||||
*/
|
||||
if (line_buf_ix > old_pos)
|
||||
printf("%.*s", (int) (line_buf_ix - old_pos),
|
||||
line_buf + old_pos);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_history_begin)
|
||||
{
|
||||
terminal_get_line_from_history(-1);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_history_end)
|
||||
{
|
||||
if (line_index > 0)
|
||||
terminal_get_line_from_history(0);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_history_up)
|
||||
{
|
||||
terminal_get_line_from_history(line_index + 1);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_history_down)
|
||||
{
|
||||
if (line_index > 0)
|
||||
terminal_get_line_from_history(line_index - 1);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_tab)
|
||||
{
|
||||
/* tab processing */
|
||||
process_tab(line_buf, line_buf_ix);
|
||||
}
|
||||
|
||||
|
||||
TERMINAL_ACTION(terminal_action_backspace)
|
||||
{
|
||||
if (line_buf_ix <= 0)
|
||||
return;
|
||||
|
||||
if (line_buf_ix == line_len) {
|
||||
printf("\b \b");
|
||||
line_len = --line_buf_ix;
|
||||
line_buf[line_len] = 0;
|
||||
} else {
|
||||
putchar('\b');
|
||||
line_buf_ix--;
|
||||
line_len--;
|
||||
memmove(line_buf + line_buf_ix,
|
||||
line_buf + line_buf_ix + 1,
|
||||
line_len - line_buf_ix + 1);
|
||||
printf("%s \b", line_buf + line_buf_ix);
|
||||
terminal_move_cursor(line_buf_ix - line_len);
|
||||
}
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_find_history_forward)
|
||||
{
|
||||
/* Search history forward */
|
||||
terminal_match_hitory(false);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_find_history_backward)
|
||||
{
|
||||
/* Search history forward */
|
||||
terminal_match_hitory(true);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_ctrl_c)
|
||||
{
|
||||
terminal_clear_line();
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_ctrl_d)
|
||||
{
|
||||
if (line_len > 0) {
|
||||
terminal_delete_char();
|
||||
} else {
|
||||
puts("");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_clear_screen)
|
||||
{
|
||||
terminal_clear_screen();
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_enter)
|
||||
{
|
||||
/*
|
||||
* On new line add line to history
|
||||
* forget history position
|
||||
*/
|
||||
history_add_line(line_buf);
|
||||
line_len = 0;
|
||||
line_buf_ix = 0;
|
||||
line_index = -1;
|
||||
/* print new line */
|
||||
putchar(c);
|
||||
prompt = noprompt;
|
||||
process_line(line_buf);
|
||||
/* clear current line */
|
||||
line_buf[0] = '\0';
|
||||
prompt = current_prompt;
|
||||
printf("%s", prompt);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_default)
|
||||
{
|
||||
char str[2] = { c, 0 };
|
||||
|
||||
if (!isprint(c))
|
||||
/*
|
||||
* TODO: remove this print once all meaningful sequences
|
||||
* are identified
|
||||
*/
|
||||
printf("char-0x%02x\n", c);
|
||||
else if (line_buf_ix < LINE_BUF_MAX - 1)
|
||||
terminal_insert_into_command_line(str);
|
||||
}
|
||||
|
||||
/* Callback to call when user hit enter during prompt for */
|
||||
static line_callback prompt_callback;
|
||||
|
||||
static KeyAction normal_actions[] = {
|
||||
{ 0, terminal_action_default },
|
||||
{ KEY_LEFT, terminal_action_left },
|
||||
{ KEY_RIGHT, terminal_action_right },
|
||||
{ KEY_HOME, terminal_action_home },
|
||||
{ KEY_END, terminal_action_end },
|
||||
{ KEY_DELETE, terminal_action_del },
|
||||
{ KEY_CLEFT, terminal_action_word_left },
|
||||
{ KEY_CRIGHT, terminal_action_word_right },
|
||||
{ KEY_SUP, terminal_action_history_begin },
|
||||
{ KEY_SDOWN, terminal_action_history_end },
|
||||
{ KEY_UP, terminal_action_history_up },
|
||||
{ KEY_DOWN, terminal_action_history_down },
|
||||
{ '\t', terminal_action_tab },
|
||||
{ KEY_BACKSPACE, terminal_action_backspace },
|
||||
{ KEY_M_n, terminal_action_find_history_forward },
|
||||
{ KEY_M_p, terminal_action_find_history_backward },
|
||||
{ KEY_C_C, terminal_action_ctrl_c },
|
||||
{ KEY_C_D, terminal_action_ctrl_d },
|
||||
{ KEY_C_L, terminal_action_clear_screen },
|
||||
{ '\r', terminal_action_enter },
|
||||
{ '\n', terminal_action_enter },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
TERMINAL_ACTION(terminal_action_answer)
|
||||
{
|
||||
putchar(c);
|
||||
|
||||
terminal_set_actions(normal_actions);
|
||||
/* Restore default prompt */
|
||||
current_prompt = prompt_buf;
|
||||
|
||||
/* No prompt for prints */
|
||||
prompt = noprompt;
|
||||
line_buf_ix = 0;
|
||||
line_len = 0;
|
||||
/* Call user function with what was typed */
|
||||
prompt_callback(line_buf);
|
||||
|
||||
line_buf[0] = 0;
|
||||
/* promot_callback could change current_prompt */
|
||||
prompt = current_prompt;
|
||||
|
||||
printf("%s", prompt);
|
||||
}
|
||||
|
||||
TERMINAL_ACTION(terminal_action_prompt_ctrl_c)
|
||||
{
|
||||
printf("^C\n");
|
||||
line_buf_ix = 0;
|
||||
line_len = 0;
|
||||
line_buf[0] = 0;
|
||||
|
||||
current_prompt = prompt_buf;
|
||||
prompt = current_prompt;
|
||||
terminal_set_actions(normal_actions);
|
||||
|
||||
printf("%s", prompt);
|
||||
}
|
||||
|
||||
static KeyAction prompt_actions[] = {
|
||||
{ 0, terminal_action_default },
|
||||
{ KEY_LEFT, terminal_action_left },
|
||||
{ KEY_RIGHT, terminal_action_right },
|
||||
{ KEY_HOME, terminal_action_home },
|
||||
{ KEY_END, terminal_action_end },
|
||||
{ KEY_DELETE, terminal_action_del },
|
||||
{ KEY_CLEFT, terminal_action_word_left },
|
||||
{ KEY_CRIGHT, terminal_action_word_right },
|
||||
{ KEY_BACKSPACE, terminal_action_backspace },
|
||||
{ KEY_C_C, terminal_action_prompt_ctrl_c },
|
||||
{ KEY_C_D, terminal_action_ctrl_d },
|
||||
{ '\r', terminal_action_answer },
|
||||
{ '\n', terminal_action_answer },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
void terminal_process_char(int c, line_callback process_line)
|
||||
{
|
||||
KeyAction *a;
|
||||
|
||||
c = terminal_convert_sequence(c);
|
||||
|
||||
/* Get action for this key */
|
||||
a = terminal_get_action(c);
|
||||
|
||||
/* No action found, get default one */
|
||||
if (a == NULL)
|
||||
a = ¤t_actions[0];
|
||||
|
||||
a->func(c, process_line);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void terminal_prompt_for(const char *s, line_callback process_line)
|
||||
{
|
||||
current_prompt = s;
|
||||
if (prompt != noprompt) {
|
||||
prompt = s;
|
||||
terminal_clear_line();
|
||||
}
|
||||
prompt_callback = process_line;
|
||||
terminal_set_actions(prompt_actions);
|
||||
}
|
||||
|
||||
static struct termios origianl_tios;
|
||||
|
||||
static void terminal_cleanup(void)
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &origianl_tios);
|
||||
}
|
||||
|
||||
void terminal_setup(void)
|
||||
{
|
||||
struct termios tios;
|
||||
|
||||
terminal_set_actions(normal_actions);
|
||||
|
||||
tcgetattr(0, &origianl_tios);
|
||||
tios = origianl_tios;
|
||||
|
||||
/*
|
||||
* Turn off echo since all editing is done by hand,
|
||||
* Ctrl-c handled internally
|
||||
*/
|
||||
tios.c_lflag &= ~(ICANON | ECHO | BRKINT | IGNBRK);
|
||||
tcsetattr(0, TCSANOW, &tios);
|
||||
|
||||
/* Restore terminal at exit */
|
||||
atexit(terminal_cleanup);
|
||||
|
||||
printf("%s", prompt);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* size of supported line */
|
||||
#define LINE_BUF_MAX 1024
|
||||
|
||||
enum key_codes {
|
||||
KEY_BACKSPACE = 0x7F,
|
||||
KEY_INSERT = 1000, /* arbitrary value */
|
||||
KEY_DELETE,
|
||||
KEY_HOME,
|
||||
KEY_END,
|
||||
KEY_PGUP,
|
||||
KEY_PGDOWN,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_CLEFT,
|
||||
KEY_CRIGHT,
|
||||
KEY_CUP,
|
||||
KEY_CDOWN,
|
||||
KEY_SLEFT,
|
||||
KEY_SRIGHT,
|
||||
KEY_SUP,
|
||||
KEY_SDOWN,
|
||||
KEY_MLEFT,
|
||||
KEY_MRIGHT,
|
||||
KEY_MUP,
|
||||
KEY_MDOWN,
|
||||
KEY_STAB,
|
||||
KEY_M_p,
|
||||
KEY_M_n
|
||||
};
|
||||
|
||||
typedef void (*line_callback)(char *);
|
||||
|
||||
void terminal_setup(void);
|
||||
int terminal_print(const char *format, ...);
|
||||
int terminal_vprint(const char *format, va_list args);
|
||||
void terminal_process_char(int c, line_callback process_line);
|
||||
void terminal_insert_into_command_line(const char *p);
|
||||
void terminal_draw_command_line(void);
|
||||
void terminal_prompt_for(const char *s, line_callback process_line);
|
||||
|
||||
void process_tab(const char *line, int len);
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 1987-2011 Free Software Foundation, Inc.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HISTORY_H_
|
||||
#define _HISTORY_H_
|
||||
|
||||
static inline void add_history(const char *c)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 1987-2011 Free Software Foundation, Inc.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _READLINE_H_
|
||||
#define _READLINE_H_
|
||||
|
||||
typedef void (*rl_vcpfunc_t)(char *c);
|
||||
typedef void (*rl_compdisp_func_t)(char **c, int i, int j);
|
||||
typedef char *(*rl_compentry_func_t)(const char *c, int i);
|
||||
typedef char **(*rl_completion_func_t)(const char *c, int i, int j);
|
||||
|
||||
#define RL_STATE_DONE 0x1000000
|
||||
#define RL_ISSTATE(x) (rl_readline_state & (x))
|
||||
|
||||
static int rl_end;
|
||||
static int rl_point;
|
||||
static int rl_readline_state;
|
||||
static int rl_erase_empty_line;
|
||||
static int rl_attempted_completion_over;
|
||||
static char *rl_prompt;
|
||||
static char *rl_line_buffer;
|
||||
static rl_compdisp_func_t rl_completion_display_matches_hook;
|
||||
static rl_completion_func_t rl_attempted_completion_function;
|
||||
|
||||
static inline void rl_callback_handler_install(const char *c, rl_vcpfunc_t f)
|
||||
{
|
||||
printf("readline not available\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline int rl_set_prompt(const char *c)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void rl_replace_line(const char *c, int i)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rl_redisplay(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline char **rl_completion_matches(const char *c, rl_compentry_func_t f)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int rl_insert_text(const char *c)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int rl_crlf(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void rl_callback_read_char(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rl_message(const char *c, ...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void rl_callback_handler_remove(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline char *rl_copy_text(int i, int j)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void rl_save_prompt(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rl_restore_prompt(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rl_forced_update_display(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 1991-2013 Free Software Foundation, Inc.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _WORDEXP_H_
|
||||
#define _WORDEXP_H_
|
||||
|
||||
#define WRDE_NOCMD 0
|
||||
|
||||
typedef struct {
|
||||
size_t we_wordc;
|
||||
char **we_wordv;
|
||||
size_t we_offs;
|
||||
} wordexp_t;
|
||||
|
||||
static inline int wordexp(const char *c, wordexp_t *w, int _i)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void wordfree(wordexp_t *__wordexp)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
Android Compatibility Test Suite results
|
||||
|
||||
Tested: 27-Nov-2014
|
||||
Android version: 5.0
|
||||
Kernel Version: 3.18
|
||||
CTS version: 5.0 R1 (android-5.0.0_r7)
|
||||
|
||||
Note:
|
||||
CTS reliable write GATT tests require using CTS from master branch
|
||||
or https://android-review.googlesource.com/99354 applied.
|
||||
|
||||
(*) Tests are disabled due to CTS quality issues. Link for reference:
|
||||
https://android.googlesource.com/platform/cts/+/0a62e4a0a9910101ccf2ccc43f6%5E!/
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
android.bluetooth.cts.BasicAdapterTest (automated tests)
|
||||
Test Name Result Notes
|
||||
-------------------------------------------------------------------------------
|
||||
testAndroidTestCaseSetupProperly PASS
|
||||
test_checkBluetoothAddress PASS
|
||||
test_enableDisable PASS
|
||||
test_getAddress PASS
|
||||
test_getBondedDevices PASS
|
||||
test_getDefaultAdapter PASS
|
||||
test_getName PASS
|
||||
test_getRemoteDevice PASS
|
||||
test_listenUsingRfcommWithServiceRecord PASS
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
com.android.cts.verifier (manual tests)
|
||||
Test Name Result Notes
|
||||
-------------------------------------------------------------------------------
|
||||
Toggle Bluetooth PASS
|
||||
BLE Client Test:
|
||||
connect N/A (*)
|
||||
discover service N/A (*)
|
||||
read/write characteristic N/A (*)
|
||||
reliable write N/A (*)
|
||||
notify characteristic N/A (*)
|
||||
read/write descriptor N/A (*)
|
||||
read RSSI N/A (*)
|
||||
disconnect N/A (*)
|
||||
BLE Server Test:
|
||||
add service N/A (*)
|
||||
connection N/A (*)
|
||||
read characteristic request N/A (*)
|
||||
write characteristic request N/A (*)
|
||||
read descriptor request N/A (*)
|
||||
write descriptor request N/A (*)
|
||||
reliable write N/A (*)
|
||||
disconnection N/A (*)
|
||||
Insecure Client PASS
|
||||
Insecure Server PASS
|
||||
Secure Client PASS
|
||||
Secure Server PASS
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define PROPERTY_VALUE_MAX 32
|
||||
#define PROPERTY_KEY_MAX 32
|
||||
|
||||
#define BLUETOOTH_MODE_PROPERTY_NAME "persist.sys.bluetooth.mode"
|
||||
#define BLUETOOTH_MODE_PROPERTY_HANDSFREE "persist.sys.bluetooth.handsfree"
|
||||
|
||||
static inline int property_get(const char *key, char *value,
|
||||
const char *default_value)
|
||||
{
|
||||
const char *prop = NULL;
|
||||
|
||||
if (!strcmp(key, BLUETOOTH_MODE_PROPERTY_NAME))
|
||||
prop = getenv("BLUETOOTH_MODE");
|
||||
|
||||
if (!strcmp(key, BLUETOOTH_MODE_PROPERTY_HANDSFREE))
|
||||
prop = getenv("BLUETOOTH_HANDSFREE_MODE");
|
||||
|
||||
if (!prop)
|
||||
prop = default_value;
|
||||
|
||||
if (prop) {
|
||||
strncpy(value, prop, PROPERTY_VALUE_MAX);
|
||||
|
||||
value[PROPERTY_VALUE_MAX - 1] = '\0';
|
||||
|
||||
return strlen(value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* property_set: returns 0 on success, < 0 on failure
|
||||
*/
|
||||
static inline int property_set(const char *key, const char *value)
|
||||
{
|
||||
static const char SYSTEM_SOCKET_PATH[] = "\0android_system";
|
||||
|
||||
struct sockaddr_un addr;
|
||||
char msg[256];
|
||||
int fd, len;
|
||||
|
||||
fd = socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
memcpy(addr.sun_path, SYSTEM_SOCKET_PATH, sizeof(SYSTEM_SOCKET_PATH));
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = snprintf(msg, sizeof(msg), "%s=%s", key, value);
|
||||
|
||||
if (send(fd, msg, len + 1, 0) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr);
|
||||
void bt_gatt_unregister(void);
|
||||
|
||||
|
||||
typedef enum {
|
||||
GATT_CLIENT,
|
||||
GATT_SERVER,
|
||||
} gatt_type_t;
|
||||
|
||||
typedef void (*gatt_conn_cb_t)(const bdaddr_t *addr, int err, void *attrib);
|
||||
|
||||
unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
|
||||
gatt_conn_cb_t func);
|
||||
bool bt_gatt_unregister_app(unsigned int id);
|
||||
|
||||
bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
|
||||
bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
|
||||
bool bt_gatt_set_security(const bdaddr_t *bdaddr, int sec_level);
|
||||
bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr);
|
||||
void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr);
|
||||
@@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hal-log.h"
|
||||
#include "hal.h"
|
||||
#include "hal-msg.h"
|
||||
#include "hal-ipc.h"
|
||||
|
||||
static const btav_callbacks_t *cbs = NULL;
|
||||
|
||||
static bool interface_ready(void)
|
||||
{
|
||||
return cbs != NULL;
|
||||
}
|
||||
|
||||
static void handle_conn_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_a2dp_conn_state *ev = buf;
|
||||
|
||||
if (cbs->connection_state_cb)
|
||||
cbs->connection_state_cb(ev->state,
|
||||
(bt_bdaddr_t *) (ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_audio_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_a2dp_audio_state *ev = buf;
|
||||
|
||||
if (cbs->audio_state_cb)
|
||||
cbs->audio_state_cb(ev->state, (bt_bdaddr_t *)(ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_audio_config(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_a2dp_audio_config *ev = buf;
|
||||
|
||||
if (cbs->audio_config_cb)
|
||||
cbs->audio_config_cb((bt_bdaddr_t *)(ev->bdaddr),
|
||||
ev->sample_rate, ev->channel_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* handlers will be called from notification thread context,
|
||||
* index in table equals to 'opcode - HAL_MINIMUM_EVENT'
|
||||
*/
|
||||
static const struct hal_ipc_handler ev_handlers[] = {
|
||||
/* HAL_EV_A2DP_CONN_STATE */
|
||||
{ handle_conn_state, false, sizeof(struct hal_ev_a2dp_conn_state) },
|
||||
/* HAL_EV_A2DP_AUDIO_STATE */
|
||||
{ handle_audio_state, false, sizeof(struct hal_ev_a2dp_audio_state) },
|
||||
/* HAL_EV_A2DP_AUDIO_CONFIG */
|
||||
{ handle_audio_config, false, sizeof(struct hal_ev_a2dp_audio_config) },
|
||||
};
|
||||
|
||||
static bt_status_t a2dp_connect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_a2dp_connect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_CONNECT,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_a2dp_disconnect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_A2DP_SINK, HAL_OP_A2DP_DISCONNECT,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t init(btav_callbacks_t *callbacks)
|
||||
{
|
||||
struct hal_cmd_register_module cmd;
|
||||
int ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (interface_ready())
|
||||
return BT_STATUS_DONE;
|
||||
|
||||
cbs = callbacks;
|
||||
|
||||
hal_ipc_register(HAL_SERVICE_ID_A2DP_SINK, ev_handlers,
|
||||
sizeof(ev_handlers)/sizeof(ev_handlers[0]));
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_A2DP_SINK;
|
||||
cmd.mode = HAL_MODE_DEFAULT;
|
||||
cmd.max_clients = 1;
|
||||
|
||||
ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
cbs = NULL;
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_A2DP_SINK);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct hal_cmd_unregister_module cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return;
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_A2DP_SINK;
|
||||
|
||||
hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_A2DP_SINK);
|
||||
|
||||
cbs = NULL;
|
||||
}
|
||||
|
||||
static btav_interface_t iface = {
|
||||
.size = sizeof(iface),
|
||||
.init = init,
|
||||
.connect = a2dp_connect,
|
||||
.disconnect = disconnect,
|
||||
.cleanup = cleanup
|
||||
};
|
||||
|
||||
btav_interface_t *bt_get_a2dp_sink_interface(void)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hal-log.h"
|
||||
#include "hal.h"
|
||||
#include "hal-msg.h"
|
||||
#include "hal-ipc.h"
|
||||
|
||||
static const btav_callbacks_t *cbs = NULL;
|
||||
|
||||
static bool interface_ready(void)
|
||||
{
|
||||
return cbs != NULL;
|
||||
}
|
||||
|
||||
static void handle_conn_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_a2dp_conn_state *ev = buf;
|
||||
|
||||
if (cbs->connection_state_cb)
|
||||
cbs->connection_state_cb(ev->state,
|
||||
(bt_bdaddr_t *) (ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_audio_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_a2dp_audio_state *ev = buf;
|
||||
|
||||
if (cbs->audio_state_cb)
|
||||
cbs->audio_state_cb(ev->state, (bt_bdaddr_t *)(ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_audio_config(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
||||
struct hal_ev_a2dp_audio_config *ev = buf;
|
||||
|
||||
if (cbs->audio_config_cb)
|
||||
cbs->audio_config_cb((bt_bdaddr_t *)(ev->bdaddr),
|
||||
ev->sample_rate, ev->channel_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* handlers will be called from notification thread context,
|
||||
* index in table equals to 'opcode - HAL_MINIMUM_EVENT'
|
||||
*/
|
||||
static const struct hal_ipc_handler ev_handlers[] = {
|
||||
/* HAL_EV_A2DP_CONN_STATE */
|
||||
{ handle_conn_state, false, sizeof(struct hal_ev_a2dp_conn_state) },
|
||||
/* HAL_EV_A2DP_AUDIO_STATE */
|
||||
{ handle_audio_state, false, sizeof(struct hal_ev_a2dp_audio_state) },
|
||||
/* HAL_EV_A2DP_AUDIO_CONFIG */
|
||||
{ handle_audio_config, false, sizeof(struct hal_ev_a2dp_audio_config) },
|
||||
};
|
||||
|
||||
static bt_status_t a2dp_connect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_a2dp_connect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_CONNECT,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_a2dp_disconnect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_A2DP, HAL_OP_A2DP_DISCONNECT,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t init(btav_callbacks_t *callbacks)
|
||||
{
|
||||
struct hal_cmd_register_module cmd;
|
||||
int ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (interface_ready())
|
||||
return BT_STATUS_DONE;
|
||||
|
||||
cbs = callbacks;
|
||||
|
||||
hal_ipc_register(HAL_SERVICE_ID_A2DP, ev_handlers,
|
||||
sizeof(ev_handlers)/sizeof(ev_handlers[0]));
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_A2DP;
|
||||
cmd.mode = HAL_MODE_DEFAULT;
|
||||
cmd.max_clients = 1;
|
||||
|
||||
ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
cbs = NULL;
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_A2DP);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct hal_cmd_unregister_module cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return;
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_A2DP;
|
||||
|
||||
hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_A2DP);
|
||||
|
||||
cbs = NULL;
|
||||
}
|
||||
|
||||
static btav_interface_t iface = {
|
||||
.size = sizeof(iface),
|
||||
.init = init,
|
||||
.connect = a2dp_connect,
|
||||
.disconnect = disconnect,
|
||||
.cleanup = cleanup
|
||||
};
|
||||
|
||||
btav_interface_t *bt_get_a2dp_interface(void)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Tieto Poland
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "audio-msg.h"
|
||||
#include "hal-audio.h"
|
||||
#include "hal-log.h"
|
||||
#include "profiles/audio/a2dp-codecs.h"
|
||||
|
||||
#define APTX_SO_NAME "libbt-aptx.so"
|
||||
|
||||
struct aptx_data {
|
||||
a2dp_aptx_t aptx;
|
||||
|
||||
void *enc;
|
||||
};
|
||||
|
||||
static const a2dp_aptx_t aptx_presets[] = {
|
||||
{
|
||||
.info =
|
||||
A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
|
||||
.frequency = APTX_SAMPLING_FREQ_44100 |
|
||||
APTX_SAMPLING_FREQ_48000,
|
||||
.channel_mode = APTX_CHANNEL_MODE_STEREO,
|
||||
},
|
||||
{
|
||||
.info =
|
||||
A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
|
||||
.frequency = APTX_SAMPLING_FREQ_48000,
|
||||
.channel_mode = APTX_CHANNEL_MODE_STEREO,
|
||||
},
|
||||
{
|
||||
.info =
|
||||
A2DP_SET_VENDOR_ID_CODEC_ID(APTX_VENDOR_ID, APTX_CODEC_ID),
|
||||
.frequency = APTX_SAMPLING_FREQ_44100,
|
||||
.channel_mode = APTX_CHANNEL_MODE_STEREO,
|
||||
},
|
||||
};
|
||||
|
||||
static void *aptx_handle;
|
||||
static int aptx_btencsize;
|
||||
static int (*aptx_init)(void *, short);
|
||||
static int (*aptx_encode)(void *, void *, void *, void *);
|
||||
|
||||
static bool aptx_load(void)
|
||||
{
|
||||
const char * (*aptx_version)(void);
|
||||
const char * (*aptx_build)(void);
|
||||
int (*aptx_sizeofenc)(void);
|
||||
|
||||
aptx_handle = dlopen(APTX_SO_NAME, RTLD_LAZY);
|
||||
if (!aptx_handle) {
|
||||
error("APTX: failed to open library %s (%s)", APTX_SO_NAME,
|
||||
dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
aptx_version = dlsym(aptx_handle, "aptxbtenc_version");
|
||||
aptx_build = dlsym(aptx_handle, "aptxbtenc_build");
|
||||
|
||||
if (aptx_version && aptx_build)
|
||||
info("APTX: using library version %s build %s", aptx_version(),
|
||||
aptx_build());
|
||||
else
|
||||
warn("APTX: cannot retrieve library version");
|
||||
|
||||
aptx_sizeofenc = dlsym(aptx_handle, "SizeofAptxbtenc");
|
||||
aptx_init = dlsym(aptx_handle, "aptxbtenc_init");
|
||||
aptx_encode = dlsym(aptx_handle, "aptxbtenc_encodestereo");
|
||||
if (!aptx_sizeofenc || !aptx_init || !aptx_encode) {
|
||||
error("APTX: failed initialize library");
|
||||
dlclose(aptx_handle);
|
||||
aptx_handle = NULL;
|
||||
return false;
|
||||
}
|
||||
aptx_btencsize = aptx_sizeofenc();
|
||||
|
||||
info("APTX: codec library initialized (size=%d)", aptx_btencsize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void aptx_unload(void)
|
||||
{
|
||||
if (!aptx_handle)
|
||||
return;
|
||||
|
||||
dlclose(aptx_handle);
|
||||
aptx_handle = NULL;
|
||||
}
|
||||
|
||||
static int aptx_get_presets(struct audio_preset *preset, size_t *len)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
size_t new_len = 0;
|
||||
uint8_t *ptr = (uint8_t *) preset;
|
||||
size_t preset_size = sizeof(*preset) + sizeof(a2dp_aptx_t);
|
||||
|
||||
DBG("");
|
||||
|
||||
count = sizeof(aptx_presets) / sizeof(aptx_presets[0]);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
preset = (struct audio_preset *) ptr;
|
||||
|
||||
if (new_len + preset_size > *len)
|
||||
break;
|
||||
|
||||
preset->len = sizeof(a2dp_aptx_t);
|
||||
memcpy(preset->data, &aptx_presets[i], preset->len);
|
||||
|
||||
new_len += preset_size;
|
||||
ptr += preset_size;
|
||||
}
|
||||
|
||||
*len = new_len;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static bool aptx_codec_init(struct audio_preset *preset, uint16_t payload_len,
|
||||
void **codec_data)
|
||||
{
|
||||
struct aptx_data *aptx_data;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (preset->len != sizeof(a2dp_aptx_t)) {
|
||||
error("APTX: preset size mismatch");
|
||||
return false;
|
||||
}
|
||||
|
||||
aptx_data = malloc(sizeof(*aptx_data));
|
||||
if (!aptx_data)
|
||||
return false;
|
||||
|
||||
memset(aptx_data, 0, sizeof(*aptx_data));
|
||||
memcpy(&aptx_data->aptx, preset->data, preset->len);
|
||||
|
||||
aptx_data->enc = calloc(1, aptx_btencsize);
|
||||
if (!aptx_data->enc) {
|
||||
error("APTX: failed to create encoder");
|
||||
free(aptx_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 1 = big-endian, this is what devices are using */
|
||||
aptx_init(aptx_data->enc, 1);
|
||||
|
||||
*codec_data = aptx_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool aptx_cleanup(void *codec_data)
|
||||
{
|
||||
struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
|
||||
|
||||
free(aptx_data->enc);
|
||||
free(codec_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool aptx_get_config(void *codec_data, struct audio_input_config *config)
|
||||
{
|
||||
struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
|
||||
|
||||
config->rate = aptx_data->aptx.frequency & APTX_SAMPLING_FREQ_48000 ?
|
||||
48000 : 44100;
|
||||
config->channels = AUDIO_CHANNEL_OUT_STEREO;
|
||||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t aptx_get_buffer_size(void *codec_data)
|
||||
{
|
||||
/* TODO: return actual value */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t aptx_get_mediapacket_duration(void *codec_data)
|
||||
{
|
||||
/* TODO: return actual value */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t aptx_encode_mediapacket(void *codec_data, const uint8_t *buffer,
|
||||
size_t len, struct media_packet *mp,
|
||||
size_t mp_data_len, size_t *written)
|
||||
{
|
||||
struct aptx_data *aptx_data = (struct aptx_data *) codec_data;
|
||||
const int16_t *ptr = (const void *) buffer;
|
||||
size_t bytes_in = 0;
|
||||
size_t bytes_out = 0;
|
||||
|
||||
while ((len - bytes_in) >= 16 && (mp_data_len - bytes_out) >= 4) {
|
||||
int pcm_l[4], pcm_r[4];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
pcm_l[i] = ptr[0];
|
||||
pcm_r[i] = ptr[1];
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
aptx_encode(aptx_data->enc, pcm_l, pcm_r, &mp->data[bytes_out]);
|
||||
|
||||
bytes_in += 16;
|
||||
bytes_out += 4;
|
||||
}
|
||||
|
||||
*written = bytes_out;
|
||||
|
||||
return bytes_in;
|
||||
}
|
||||
|
||||
static bool aptx_update_qos(void *codec_data, uint8_t op)
|
||||
{
|
||||
/*
|
||||
* aptX has constant bitrate of 352kbps (with constant 4:1 compression
|
||||
* ratio) thus QoS is not possible here.
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct audio_codec codec = {
|
||||
.type = A2DP_CODEC_VENDOR,
|
||||
.use_rtp = false,
|
||||
|
||||
.load = aptx_load,
|
||||
.unload = aptx_unload,
|
||||
|
||||
.get_presets = aptx_get_presets,
|
||||
|
||||
.init = aptx_codec_init,
|
||||
.cleanup = aptx_cleanup,
|
||||
.get_config = aptx_get_config,
|
||||
.get_buffer_size = aptx_get_buffer_size,
|
||||
.get_mediapacket_duration = aptx_get_mediapacket_duration,
|
||||
.encode_mediapacket = aptx_encode_mediapacket,
|
||||
.update_qos = aptx_update_qos,
|
||||
};
|
||||
|
||||
const struct audio_codec *codec_aptx(void)
|
||||
{
|
||||
return &codec;
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sbc/sbc.h>
|
||||
#include "audio-msg.h"
|
||||
#include "hal-audio.h"
|
||||
#include "hal-log.h"
|
||||
#include "../profiles/audio/a2dp-codecs.h"
|
||||
|
||||
#define MAX_FRAMES_IN_PAYLOAD 15
|
||||
|
||||
#define SBC_QUALITY_MIN_BITPOOL 33
|
||||
#define SBC_QUALITY_STEP 5
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
|
||||
struct rtp_payload {
|
||||
unsigned frame_count:4;
|
||||
unsigned rfa0:1;
|
||||
unsigned is_last_fragment:1;
|
||||
unsigned is_first_fragment:1;
|
||||
unsigned is_fragmented:1;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
struct rtp_payload {
|
||||
unsigned is_fragmented:1;
|
||||
unsigned is_first_fragment:1;
|
||||
unsigned is_last_fragment:1;
|
||||
unsigned rfa0:1;
|
||||
unsigned frame_count:4;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
struct media_packet_sbc {
|
||||
struct media_packet_rtp hdr;
|
||||
struct rtp_payload payload;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct sbc_data {
|
||||
a2dp_sbc_t sbc;
|
||||
|
||||
sbc_t enc;
|
||||
|
||||
uint16_t payload_len;
|
||||
|
||||
size_t in_frame_len;
|
||||
size_t in_buf_size;
|
||||
|
||||
size_t out_frame_len;
|
||||
|
||||
unsigned frame_duration;
|
||||
unsigned frames_per_packet;
|
||||
};
|
||||
|
||||
static const a2dp_sbc_t sbc_presets[] = {
|
||||
{
|
||||
.frequency = SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000,
|
||||
.channel_mode = SBC_CHANNEL_MODE_MONO |
|
||||
SBC_CHANNEL_MODE_DUAL_CHANNEL |
|
||||
SBC_CHANNEL_MODE_STEREO |
|
||||
SBC_CHANNEL_MODE_JOINT_STEREO,
|
||||
.subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8,
|
||||
.allocation_method = SBC_ALLOCATION_SNR |
|
||||
SBC_ALLOCATION_LOUDNESS,
|
||||
.block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 |
|
||||
SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16,
|
||||
.min_bitpool = SBC_MIN_BITPOOL,
|
||||
.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100,
|
||||
},
|
||||
{
|
||||
.frequency = SBC_SAMPLING_FREQ_44100,
|
||||
.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
|
||||
.subbands = SBC_SUBBANDS_8,
|
||||
.allocation_method = SBC_ALLOCATION_LOUDNESS,
|
||||
.block_length = SBC_BLOCK_LENGTH_16,
|
||||
.min_bitpool = SBC_MIN_BITPOOL,
|
||||
.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100,
|
||||
},
|
||||
{
|
||||
.frequency = SBC_SAMPLING_FREQ_48000,
|
||||
.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO,
|
||||
.subbands = SBC_SUBBANDS_8,
|
||||
.allocation_method = SBC_ALLOCATION_LOUDNESS,
|
||||
.block_length = SBC_BLOCK_LENGTH_16,
|
||||
.min_bitpool = SBC_MIN_BITPOOL,
|
||||
.max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_48000,
|
||||
},
|
||||
};
|
||||
|
||||
static int sbc_get_presets(struct audio_preset *preset, size_t *len)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
size_t new_len = 0;
|
||||
uint8_t *ptr = (uint8_t *) preset;
|
||||
size_t preset_size = sizeof(*preset) + sizeof(a2dp_sbc_t);
|
||||
|
||||
count = sizeof(sbc_presets) / sizeof(sbc_presets[0]);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
preset = (struct audio_preset *) ptr;
|
||||
|
||||
if (new_len + preset_size > *len)
|
||||
break;
|
||||
|
||||
preset->len = sizeof(a2dp_sbc_t);
|
||||
memcpy(preset->data, &sbc_presets[i], preset->len);
|
||||
|
||||
new_len += preset_size;
|
||||
ptr += preset_size;
|
||||
}
|
||||
|
||||
*len = new_len;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int sbc_freq2int(uint8_t freq)
|
||||
{
|
||||
switch (freq) {
|
||||
case SBC_SAMPLING_FREQ_16000:
|
||||
return 16000;
|
||||
case SBC_SAMPLING_FREQ_32000:
|
||||
return 32000;
|
||||
case SBC_SAMPLING_FREQ_44100:
|
||||
return 44100;
|
||||
case SBC_SAMPLING_FREQ_48000:
|
||||
return 48000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sbc_mode2str(uint8_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SBC_CHANNEL_MODE_MONO:
|
||||
return "Mono";
|
||||
case SBC_CHANNEL_MODE_DUAL_CHANNEL:
|
||||
return "DualChannel";
|
||||
case SBC_CHANNEL_MODE_STEREO:
|
||||
return "Stereo";
|
||||
case SBC_CHANNEL_MODE_JOINT_STEREO:
|
||||
return "JointStereo";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
static int sbc_blocks2int(uint8_t blocks)
|
||||
{
|
||||
switch (blocks) {
|
||||
case SBC_BLOCK_LENGTH_4:
|
||||
return 4;
|
||||
case SBC_BLOCK_LENGTH_8:
|
||||
return 8;
|
||||
case SBC_BLOCK_LENGTH_12:
|
||||
return 12;
|
||||
case SBC_BLOCK_LENGTH_16:
|
||||
return 16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int sbc_subbands2int(uint8_t subbands)
|
||||
{
|
||||
switch (subbands) {
|
||||
case SBC_SUBBANDS_4:
|
||||
return 4;
|
||||
case SBC_SUBBANDS_8:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sbc_allocation2str(uint8_t allocation)
|
||||
{
|
||||
switch (allocation) {
|
||||
case SBC_ALLOCATION_SNR:
|
||||
return "SNR";
|
||||
case SBC_ALLOCATION_LOUDNESS:
|
||||
return "Loudness";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
static void sbc_init_encoder(struct sbc_data *sbc_data)
|
||||
{
|
||||
a2dp_sbc_t *in = &sbc_data->sbc;
|
||||
sbc_t *out = &sbc_data->enc;
|
||||
|
||||
sbc_init_a2dp(out, 0L, in, sizeof(*in));
|
||||
|
||||
out->endian = SBC_LE;
|
||||
out->bitpool = in->max_bitpool;
|
||||
|
||||
DBG("frequency=%d channel_mode=%s block_length=%d subbands=%d allocation=%s bitpool=%d-%d",
|
||||
sbc_freq2int(in->frequency),
|
||||
sbc_mode2str(in->channel_mode),
|
||||
sbc_blocks2int(in->block_length),
|
||||
sbc_subbands2int(in->subbands),
|
||||
sbc_allocation2str(in->allocation_method),
|
||||
in->min_bitpool, in->max_bitpool);
|
||||
}
|
||||
|
||||
static void sbc_codec_calculate(struct sbc_data *sbc_data)
|
||||
{
|
||||
size_t in_frame_len;
|
||||
size_t out_frame_len;
|
||||
size_t num_frames;
|
||||
|
||||
in_frame_len = sbc_get_codesize(&sbc_data->enc);
|
||||
out_frame_len = sbc_get_frame_length(&sbc_data->enc);
|
||||
num_frames = sbc_data->payload_len / out_frame_len;
|
||||
|
||||
if (num_frames > MAX_FRAMES_IN_PAYLOAD)
|
||||
num_frames = MAX_FRAMES_IN_PAYLOAD;
|
||||
|
||||
sbc_data->in_frame_len = in_frame_len;
|
||||
sbc_data->in_buf_size = num_frames * in_frame_len;
|
||||
|
||||
sbc_data->out_frame_len = out_frame_len;
|
||||
|
||||
sbc_data->frame_duration = sbc_get_frame_duration(&sbc_data->enc);
|
||||
sbc_data->frames_per_packet = num_frames;
|
||||
|
||||
DBG("in_frame_len=%zu out_frame_len=%zu frames_per_packet=%zu",
|
||||
in_frame_len, out_frame_len, num_frames);
|
||||
}
|
||||
|
||||
static bool sbc_codec_init(struct audio_preset *preset, uint16_t payload_len,
|
||||
void **codec_data)
|
||||
{
|
||||
struct sbc_data *sbc_data;
|
||||
|
||||
if (preset->len != sizeof(a2dp_sbc_t)) {
|
||||
error("SBC: preset size mismatch");
|
||||
return false;
|
||||
}
|
||||
|
||||
sbc_data = calloc(sizeof(struct sbc_data), 1);
|
||||
if (!sbc_data)
|
||||
return false;
|
||||
|
||||
memcpy(&sbc_data->sbc, preset->data, preset->len);
|
||||
|
||||
sbc_init_encoder(sbc_data);
|
||||
|
||||
sbc_data->payload_len = payload_len;
|
||||
|
||||
sbc_codec_calculate(sbc_data);
|
||||
|
||||
*codec_data = sbc_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sbc_cleanup(void *codec_data)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
|
||||
sbc_finish(&sbc_data->enc);
|
||||
free(codec_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sbc_get_config(void *codec_data, struct audio_input_config *config)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
|
||||
switch (sbc_data->sbc.frequency) {
|
||||
case SBC_SAMPLING_FREQ_16000:
|
||||
config->rate = 16000;
|
||||
break;
|
||||
case SBC_SAMPLING_FREQ_32000:
|
||||
config->rate = 32000;
|
||||
break;
|
||||
case SBC_SAMPLING_FREQ_44100:
|
||||
config->rate = 44100;
|
||||
break;
|
||||
case SBC_SAMPLING_FREQ_48000:
|
||||
config->rate = 48000;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
config->channels = sbc_data->sbc.channel_mode == SBC_CHANNEL_MODE_MONO ?
|
||||
AUDIO_CHANNEL_OUT_MONO :
|
||||
AUDIO_CHANNEL_OUT_STEREO;
|
||||
config->format = AUDIO_FORMAT_PCM_16_BIT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t sbc_get_buffer_size(void *codec_data)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
|
||||
return sbc_data->in_buf_size;
|
||||
}
|
||||
|
||||
static size_t sbc_get_mediapacket_duration(void *codec_data)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
|
||||
return sbc_data->frame_duration * sbc_data->frames_per_packet;
|
||||
}
|
||||
|
||||
static ssize_t sbc_encode_mediapacket(void *codec_data, const uint8_t *buffer,
|
||||
size_t len, struct media_packet *mp,
|
||||
size_t mp_data_len, size_t *written)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
struct media_packet_sbc *mp_sbc = (struct media_packet_sbc *) mp;
|
||||
size_t consumed = 0;
|
||||
size_t encoded = 0;
|
||||
uint8_t frame_count = 0;
|
||||
|
||||
mp_data_len -= sizeof(mp_sbc->payload);
|
||||
|
||||
while (len - consumed >= sbc_data->in_frame_len &&
|
||||
mp_data_len - encoded >= sbc_data->out_frame_len &&
|
||||
frame_count < sbc_data->frames_per_packet) {
|
||||
ssize_t read;
|
||||
ssize_t written = 0;
|
||||
|
||||
read = sbc_encode(&sbc_data->enc, buffer + consumed,
|
||||
sbc_data->in_frame_len, mp_sbc->data + encoded,
|
||||
mp_data_len - encoded, &written);
|
||||
|
||||
if (read < 0) {
|
||||
error("SBC: failed to encode block at frame %d (%zd)",
|
||||
frame_count, read);
|
||||
break;
|
||||
}
|
||||
|
||||
frame_count++;
|
||||
consumed += read;
|
||||
encoded += written;
|
||||
}
|
||||
|
||||
*written = encoded + sizeof(mp_sbc->payload);
|
||||
mp_sbc->payload.frame_count = frame_count;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static bool sbc_update_qos(void *codec_data, uint8_t op)
|
||||
{
|
||||
struct sbc_data *sbc_data = (struct sbc_data *) codec_data;
|
||||
uint8_t curr_bitpool = sbc_data->enc.bitpool;
|
||||
uint8_t new_bitpool = curr_bitpool;
|
||||
|
||||
switch (op) {
|
||||
case QOS_POLICY_DEFAULT:
|
||||
new_bitpool = sbc_data->sbc.max_bitpool;
|
||||
break;
|
||||
|
||||
case QOS_POLICY_DECREASE:
|
||||
if (curr_bitpool > SBC_QUALITY_MIN_BITPOOL) {
|
||||
new_bitpool = curr_bitpool - SBC_QUALITY_STEP;
|
||||
if (new_bitpool < SBC_QUALITY_MIN_BITPOOL)
|
||||
new_bitpool = SBC_QUALITY_MIN_BITPOOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_bitpool == curr_bitpool)
|
||||
return false;
|
||||
|
||||
sbc_data->enc.bitpool = new_bitpool;
|
||||
|
||||
sbc_codec_calculate(sbc_data);
|
||||
|
||||
info("SBC: bitpool changed: %d -> %d", curr_bitpool, new_bitpool);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct audio_codec codec = {
|
||||
.type = A2DP_CODEC_SBC,
|
||||
.use_rtp = true,
|
||||
|
||||
.get_presets = sbc_get_presets,
|
||||
|
||||
.init = sbc_codec_init,
|
||||
.cleanup = sbc_cleanup,
|
||||
.get_config = sbc_get_config,
|
||||
.get_buffer_size = sbc_get_buffer_size,
|
||||
.get_mediapacket_duration = sbc_get_mediapacket_duration,
|
||||
.encode_mediapacket = sbc_encode_mediapacket,
|
||||
.update_qos = sbc_update_qos,
|
||||
};
|
||||
|
||||
const struct audio_codec *codec_sbc(void)
|
||||
{
|
||||
return &codec;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <hardware/audio.h>
|
||||
|
||||
#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
|
||||
|
||||
struct media_packet {
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct media_packet_rtp {
|
||||
struct rtp_header hdr;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct audio_input_config {
|
||||
uint32_t rate;
|
||||
uint32_t channels;
|
||||
audio_format_t format;
|
||||
};
|
||||
|
||||
struct audio_codec {
|
||||
uint8_t type;
|
||||
bool use_rtp;
|
||||
|
||||
bool (*load) (void);
|
||||
void (*unload) (void);
|
||||
|
||||
int (*get_presets) (struct audio_preset *preset, size_t *len);
|
||||
|
||||
bool (*init) (struct audio_preset *preset, uint16_t mtu,
|
||||
void **codec_data);
|
||||
bool (*cleanup) (void *codec_data);
|
||||
bool (*get_config) (void *codec_data,
|
||||
struct audio_input_config *config);
|
||||
size_t (*get_buffer_size) (void *codec_data);
|
||||
size_t (*get_mediapacket_duration) (void *codec_data);
|
||||
ssize_t (*encode_mediapacket) (void *codec_data, const uint8_t *buffer,
|
||||
size_t len, struct media_packet *mp,
|
||||
size_t mp_data_len, size_t *written);
|
||||
bool (*update_qos) (void *codec_data, uint8_t op);
|
||||
};
|
||||
|
||||
#define QOS_POLICY_DEFAULT 0x00
|
||||
#define QOS_POLICY_DECREASE 0x01
|
||||
|
||||
typedef const struct audio_codec * (*audio_codec_get_t) (void);
|
||||
|
||||
const struct audio_codec *codec_sbc(void);
|
||||
const struct audio_codec *codec_aptx(void);
|
||||
@@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hal-utils.h"
|
||||
#include "hal-log.h"
|
||||
#include "hal.h"
|
||||
#include "hal-msg.h"
|
||||
#include "ipc-common.h"
|
||||
#include "hal-ipc.h"
|
||||
|
||||
static const btrc_ctrl_callbacks_t *cbs = NULL;
|
||||
|
||||
static bool interface_ready(void)
|
||||
{
|
||||
return cbs != NULL;
|
||||
}
|
||||
|
||||
static void handle_connection_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_ctrl_conn_state *ev = buf;
|
||||
|
||||
if (cbs->connection_state_cb)
|
||||
cbs->connection_state_cb(ev->state,
|
||||
(bt_bdaddr_t *) (ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_passthrough_rsp(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_ctrl_passthrough_rsp *ev = buf;
|
||||
|
||||
if (cbs->passthrough_rsp_cb)
|
||||
cbs->passthrough_rsp_cb(ev->id, ev->key_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* handlers will be called from notification thread context,
|
||||
* index in table equals to 'opcode - HAL_MINIMUM_EVENT'
|
||||
*/
|
||||
static const struct hal_ipc_handler ev_handlers[] = {
|
||||
/* HAL_EV_AVRCP_CTRL_CONN_STATE */
|
||||
{ handle_connection_state, false,
|
||||
sizeof(struct hal_ev_avrcp_ctrl_conn_state) },
|
||||
/* HAL_EV_AVRCP_CTRL_PASSTHROUGH_RSP */
|
||||
{ handle_passthrough_rsp, false,
|
||||
sizeof(struct hal_ev_avrcp_ctrl_passthrough_rsp) },
|
||||
};
|
||||
|
||||
static bt_status_t init(btrc_ctrl_callbacks_t *callbacks)
|
||||
{
|
||||
struct hal_cmd_register_module cmd;
|
||||
int ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (interface_ready())
|
||||
return BT_STATUS_DONE;
|
||||
|
||||
cbs = callbacks;
|
||||
|
||||
hal_ipc_register(HAL_SERVICE_ID_AVRCP_CTRL, ev_handlers,
|
||||
sizeof(ev_handlers) / sizeof(ev_handlers[0]));
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_AVRCP_CTRL;
|
||||
cmd.mode = HAL_MODE_DEFAULT;
|
||||
cmd.max_clients = 1;
|
||||
|
||||
ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
cbs = NULL;
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_AVRCP_CTRL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t send_pass_through_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code,
|
||||
uint8_t key_state)
|
||||
{
|
||||
struct hal_cmd_avrcp_ctrl_send_passthrough cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
cmd.key_code = key_code;
|
||||
cmd.key_state = key_state;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP_CTRL,
|
||||
HAL_OP_AVRCP_CTRL_SEND_PASSTHROUGH,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct hal_cmd_unregister_module cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return;
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_AVRCP_CTRL;
|
||||
|
||||
hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_AVRCP_CTRL);
|
||||
|
||||
cbs = NULL;
|
||||
}
|
||||
|
||||
static btrc_ctrl_interface_t iface = {
|
||||
.size = sizeof(iface),
|
||||
.init = init,
|
||||
.send_pass_through_cmd = send_pass_through_cmd,
|
||||
.cleanup = cleanup
|
||||
};
|
||||
|
||||
btrc_ctrl_interface_t *bt_get_avrcp_ctrl_interface(void)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
@@ -0,0 +1,678 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hal-utils.h"
|
||||
#include "hal-log.h"
|
||||
#include "hal.h"
|
||||
#include "hal-msg.h"
|
||||
#include "ipc-common.h"
|
||||
#include "hal-ipc.h"
|
||||
|
||||
static const btrc_callbacks_t *cbs = NULL;
|
||||
|
||||
static bool interface_ready(void)
|
||||
{
|
||||
return cbs != NULL;
|
||||
}
|
||||
|
||||
static void handle_remote_features(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_remote_features *ev = buf;
|
||||
|
||||
if (cbs->remote_features_cb)
|
||||
cbs->remote_features_cb((bt_bdaddr_t *) (ev->bdaddr),
|
||||
ev->features);
|
||||
}
|
||||
|
||||
static void handle_get_play_status(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
if (cbs->get_play_status_cb)
|
||||
cbs->get_play_status_cb();
|
||||
}
|
||||
|
||||
static void handle_list_player_attrs(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
if (cbs->list_player_app_attr_cb)
|
||||
cbs->list_player_app_attr_cb();
|
||||
}
|
||||
|
||||
static void handle_list_player_values(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_list_player_values *ev = buf;
|
||||
|
||||
if (cbs->list_player_app_values_cb)
|
||||
cbs->list_player_app_values_cb(ev->attr);
|
||||
}
|
||||
|
||||
static void handle_get_player_values(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_get_player_values *ev = buf;
|
||||
btrc_player_attr_t attrs[4];
|
||||
int i;
|
||||
|
||||
if (!cbs->get_player_app_value_cb)
|
||||
return;
|
||||
|
||||
/* Convert uint8_t array to btrc_player_attr_t array */
|
||||
for (i = 0; i < ev->number; i++)
|
||||
attrs[i] = ev->attrs[i];
|
||||
|
||||
cbs->get_player_app_value_cb(ev->number, attrs);
|
||||
}
|
||||
|
||||
static void handle_get_player_attrs_text(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_get_player_attrs_text *ev = buf;
|
||||
btrc_player_attr_t attrs[4];
|
||||
int i;
|
||||
|
||||
if (!cbs->get_player_app_attrs_text_cb)
|
||||
return;
|
||||
|
||||
/* Convert uint8_t array to btrc_player_attr_t array */
|
||||
for (i = 0; i < ev->number; i++)
|
||||
attrs[i] = ev->attrs[i];
|
||||
|
||||
cbs->get_player_app_attrs_text_cb(ev->number, attrs);
|
||||
}
|
||||
|
||||
static void handle_get_player_values_text(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_get_player_values_text *ev = buf;
|
||||
|
||||
if (cbs->get_player_app_values_text_cb)
|
||||
cbs->get_player_app_values_text_cb(ev->attr, ev->number,
|
||||
ev->values);
|
||||
}
|
||||
|
||||
static void handle_set_player_value(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_set_player_values *ev = buf;
|
||||
struct hal_avrcp_player_attr_value *attrs;
|
||||
btrc_player_settings_t values;
|
||||
int i;
|
||||
|
||||
if (!cbs->set_player_app_value_cb)
|
||||
return;
|
||||
|
||||
attrs = (struct hal_avrcp_player_attr_value *) ev->attrs;
|
||||
|
||||
/* Convert to btrc_player_settings_t */
|
||||
values.num_attr = ev->number;
|
||||
for (i = 0; i < ev->number; i++) {
|
||||
values.attr_ids[i] = attrs[i].attr;
|
||||
values.attr_values[i] = attrs[i].value;
|
||||
}
|
||||
|
||||
cbs->set_player_app_value_cb(&values);
|
||||
}
|
||||
|
||||
static void handle_get_element_attrs(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_get_element_attrs *ev = buf;
|
||||
btrc_media_attr_t attrs[BTRC_MAX_APP_SETTINGS];
|
||||
int i;
|
||||
|
||||
if (!cbs->get_element_attr_cb)
|
||||
return;
|
||||
|
||||
/* Convert uint8_t array to btrc_media_attr_t array */
|
||||
for (i = 0; i < ev->number; i++)
|
||||
attrs[i] = ev->attrs[i];
|
||||
|
||||
cbs->get_element_attr_cb(ev->number, attrs);
|
||||
}
|
||||
|
||||
static void handle_register_notification(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_register_notification *ev = buf;
|
||||
|
||||
if (cbs->register_notification_cb)
|
||||
cbs->register_notification_cb(ev->event, ev->param);
|
||||
}
|
||||
|
||||
static void handle_volume_changed(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_volume_changed *ev = buf;
|
||||
|
||||
if (cbs->volume_change_cb)
|
||||
cbs->volume_change_cb(ev->volume, ev->type);
|
||||
}
|
||||
|
||||
static void handle_passthrough_cmd(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_avrcp_passthrough_cmd *ev = buf;
|
||||
|
||||
if (cbs->passthrough_cmd_cb)
|
||||
cbs->passthrough_cmd_cb(ev->id, ev->state);
|
||||
}
|
||||
|
||||
/*
|
||||
* handlers will be called from notification thread context,
|
||||
* index in table equals to 'opcode - HAL_MINIMUM_EVENT'
|
||||
*/
|
||||
static const struct hal_ipc_handler ev_handlers[] = {
|
||||
/* HAL_EV_AVRCP_REMOTE_FEATURES */
|
||||
{ handle_remote_features, false,
|
||||
sizeof(struct hal_ev_avrcp_remote_features) },
|
||||
/* HAL_EV_AVRCP_GET_PLAY_STATUS */
|
||||
{ handle_get_play_status, false, 0 },
|
||||
/* HAL_EV_AVRCP_LIST_PLAYER_ATTRS */
|
||||
{ handle_list_player_attrs, false, 0 },
|
||||
/* HAL_EV_AVRCP_LIST_PLAYER_VALUES */
|
||||
{ handle_list_player_values, false,
|
||||
sizeof(struct hal_ev_avrcp_list_player_values) },
|
||||
/* HAL_EV_AVRCP_GET_PLAYER_VALUES */
|
||||
{ handle_get_player_values, true,
|
||||
sizeof(struct hal_ev_avrcp_get_player_values) },
|
||||
/* HAL_EV_AVRCP_GET_PLAYER_ATTRS_TEXT */
|
||||
{ handle_get_player_attrs_text, true,
|
||||
sizeof(struct hal_ev_avrcp_get_player_attrs_text) },
|
||||
/* HAL_EV_AVRCP_GET_PLAYER_VALUES_TEXT */
|
||||
{ handle_get_player_values_text, true,
|
||||
sizeof(struct hal_ev_avrcp_get_player_values_text) },
|
||||
/* HAL_EV_AVRCP_SET_PLAYER_VALUES */
|
||||
{ handle_set_player_value, true,
|
||||
sizeof(struct hal_ev_avrcp_set_player_values) },
|
||||
/* HAL_EV_AVRCP_GET_ELEMENT_ATTRS */
|
||||
{ handle_get_element_attrs, true,
|
||||
sizeof(struct hal_ev_avrcp_get_element_attrs) },
|
||||
/* HAL_EV_AVRCP_REGISTER_NOTIFICATION */
|
||||
{ handle_register_notification, false,
|
||||
sizeof(struct hal_ev_avrcp_register_notification) },
|
||||
/* HAL_EV_AVRCP_VOLUME_CHANGED */
|
||||
{ handle_volume_changed, false,
|
||||
sizeof(struct hal_ev_avrcp_volume_changed) },
|
||||
/* HAL_EV_AVRCP_PASSTHROUGH_CMD */
|
||||
{ handle_passthrough_cmd, false,
|
||||
sizeof(struct hal_ev_avrcp_passthrough_cmd) },
|
||||
};
|
||||
|
||||
static bt_status_t init(btrc_callbacks_t *callbacks)
|
||||
{
|
||||
struct hal_cmd_register_module cmd;
|
||||
int ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (interface_ready())
|
||||
return BT_STATUS_DONE;
|
||||
|
||||
cbs = callbacks;
|
||||
|
||||
hal_ipc_register(HAL_SERVICE_ID_AVRCP, ev_handlers,
|
||||
sizeof(ev_handlers) / sizeof(ev_handlers[0]));
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_AVRCP;
|
||||
cmd.mode = HAL_MODE_DEFAULT;
|
||||
cmd.max_clients = 1;
|
||||
|
||||
ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
cbs = NULL;
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_AVRCP);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t get_play_status_rsp(btrc_play_status_t status,
|
||||
uint32_t song_len, uint32_t song_pos)
|
||||
{
|
||||
struct hal_cmd_avrcp_get_play_status cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.status = status;
|
||||
cmd.duration = song_len;
|
||||
cmd.position = song_pos;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP, HAL_OP_AVRCP_GET_PLAY_STATUS,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t list_player_app_attr_rsp(int num_attr,
|
||||
btrc_player_attr_t *p_attrs)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_list_player_attrs *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (num_attr < 0)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
len = sizeof(*cmd) + num_attr;
|
||||
if (len > IPC_MTU)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
cmd->number = num_attr;
|
||||
memcpy(cmd->attrs, p_attrs, num_attr);
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_LIST_PLAYER_ATTRS,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t list_player_app_value_rsp(int num_val, uint8_t *p_vals)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_list_player_values *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (num_val < 0)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
len = sizeof(*cmd) + num_val;
|
||||
|
||||
if (len > IPC_MTU)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
cmd->number = num_val;
|
||||
memcpy(cmd->values, p_vals, num_val);
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_LIST_PLAYER_VALUES,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t get_player_app_value_rsp(btrc_player_settings_t *p_vals)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_get_player_attrs *cmd = (void *) buf;
|
||||
size_t len, attrs_len;
|
||||
int i;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (!p_vals)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
attrs_len = p_vals->num_attr *
|
||||
sizeof(struct hal_avrcp_player_attr_value);
|
||||
len = sizeof(*cmd) + attrs_len;
|
||||
|
||||
if (len > IPC_MTU)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
cmd->number = p_vals->num_attr;
|
||||
|
||||
for (i = 0; i < p_vals->num_attr; i++) {
|
||||
cmd->attrs[i].attr = p_vals->attr_ids[i];
|
||||
cmd->attrs[i].value = p_vals->attr_values[i];
|
||||
}
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_GET_PLAYER_ATTRS,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int write_text(uint8_t *ptr, uint8_t id, uint8_t *text, size_t *len)
|
||||
{
|
||||
struct hal_avrcp_player_setting_text *value = (void *) ptr;
|
||||
size_t attr_len = sizeof(*value);
|
||||
|
||||
if (attr_len + *len > IPC_MTU)
|
||||
return 0;
|
||||
|
||||
value->id = id;
|
||||
value->len = strnlen((const char *) text, BTRC_MAX_ATTR_STR_LEN);
|
||||
|
||||
*len += attr_len;
|
||||
|
||||
if (value->len + *len > IPC_MTU)
|
||||
value->len = IPC_MTU - *len;
|
||||
|
||||
memcpy(value->text, text, value->len);
|
||||
|
||||
*len += value->len;
|
||||
|
||||
return attr_len + value->len;
|
||||
}
|
||||
|
||||
static uint8_t write_player_setting_text(uint8_t *ptr, uint8_t num_attr,
|
||||
btrc_player_setting_text_t *p_attrs,
|
||||
size_t *len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_attr && *len < IPC_MTU; i++) {
|
||||
int ret;
|
||||
|
||||
ret = write_text(ptr, p_attrs[i].id, p_attrs[i].text, len);
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
ptr += ret;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static bt_status_t get_player_app_attr_text_rsp(int num_attr,
|
||||
btrc_player_setting_text_t *p_attrs)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_get_player_attrs_text *cmd = (void *) buf;
|
||||
uint8_t *ptr;
|
||||
size_t len;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (num_attr < 0 || num_attr > BTRC_MAX_APP_SETTINGS)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
ptr = (uint8_t *) &cmd->attrs[0];
|
||||
cmd->number = write_player_setting_text(ptr, num_attr, p_attrs, &len);
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_GET_PLAYER_ATTRS_TEXT,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t get_player_app_value_text_rsp(int num_val,
|
||||
btrc_player_setting_text_t *p_vals)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_get_player_values_text *cmd = (void *) buf;
|
||||
uint8_t *ptr;
|
||||
size_t len;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (num_val < 0)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
ptr = (uint8_t *) &cmd->values[0];
|
||||
cmd->number = write_player_setting_text(ptr, num_val, p_vals, &len);
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_GET_PLAYER_VALUES_TEXT,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static uint8_t write_element_attr_text(uint8_t *ptr, uint8_t num_attr,
|
||||
btrc_element_attr_val_t *p_attrs,
|
||||
size_t *len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_attr && *len < IPC_MTU; i++) {
|
||||
int ret;
|
||||
|
||||
ret = write_text(ptr, p_attrs[i].attr_id, p_attrs[i].text, len);
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
ptr += ret;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static bt_status_t get_element_attr_rsp(uint8_t num_attr,
|
||||
btrc_element_attr_val_t *p_attrs)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_get_element_attrs_text *cmd = (void *) buf;
|
||||
size_t len;
|
||||
uint8_t *ptr;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
ptr = (uint8_t *) &cmd->values[0];
|
||||
cmd->number = write_element_attr_text(ptr, num_attr, p_attrs, &len);
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_GET_ELEMENT_ATTRS_TEXT,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t set_player_app_value_rsp(btrc_status_t rsp_status)
|
||||
{
|
||||
struct hal_cmd_avrcp_set_player_attrs_value cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.status = rsp_status;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_SET_PLAYER_ATTRS_VALUE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t play_status_changed_rsp(btrc_notification_type_t type,
|
||||
btrc_play_status_t *play_status)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_register_notification *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
cmd->event = BTRC_EVT_PLAY_STATUS_CHANGED;
|
||||
cmd->type = type;
|
||||
cmd->len = 1;
|
||||
memcpy(cmd->data, play_status, cmd->len);
|
||||
|
||||
len = sizeof(*cmd) + cmd->len;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t track_change_rsp(btrc_notification_type_t type,
|
||||
btrc_uid_t *track)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_register_notification *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
cmd->event = BTRC_EVT_TRACK_CHANGE;
|
||||
cmd->type = type;
|
||||
cmd->len = sizeof(*track);
|
||||
memcpy(cmd->data, track, cmd->len);
|
||||
|
||||
len = sizeof(*cmd) + cmd->len;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t track_reached_end_rsp(btrc_notification_type_t type)
|
||||
{
|
||||
struct hal_cmd_avrcp_register_notification cmd;
|
||||
|
||||
cmd.event = BTRC_EVT_TRACK_REACHED_END;
|
||||
cmd.type = type;
|
||||
cmd.len = 0;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t track_reached_start_rsp(btrc_notification_type_t type)
|
||||
{
|
||||
struct hal_cmd_avrcp_register_notification cmd;
|
||||
|
||||
cmd.event = BTRC_EVT_TRACK_REACHED_START;
|
||||
cmd.type = type;
|
||||
cmd.len = 0;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t play_pos_changed_rsp(btrc_notification_type_t type,
|
||||
uint32_t *song_pos)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_register_notification *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
cmd->event = BTRC_EVT_PLAY_POS_CHANGED;
|
||||
cmd->type = type;
|
||||
cmd->len = sizeof(*song_pos);
|
||||
memcpy(cmd->data, song_pos, cmd->len);
|
||||
|
||||
len = sizeof(*cmd) + cmd->len;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t settings_changed_rsp(btrc_notification_type_t type,
|
||||
btrc_player_settings_t *player_setting)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_avrcp_register_notification *cmd = (void *) buf;
|
||||
struct hal_avrcp_player_attr_value *attrs;
|
||||
size_t len, param_len;
|
||||
int i;
|
||||
|
||||
param_len = player_setting->num_attr * sizeof(*attrs);
|
||||
len = sizeof(*cmd) + param_len;
|
||||
|
||||
if (len > IPC_MTU)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
cmd->event = BTRC_EVT_APP_SETTINGS_CHANGED;
|
||||
cmd->type = type;
|
||||
cmd->len = param_len;
|
||||
|
||||
attrs = (struct hal_avrcp_player_attr_value *) &cmd->data[0];
|
||||
for (i = 0; i < player_setting->num_attr; i++) {
|
||||
attrs[i].attr = player_setting->attr_ids[i];
|
||||
attrs[i].value = player_setting->attr_values[i];
|
||||
}
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP,
|
||||
HAL_OP_AVRCP_REGISTER_NOTIFICATION,
|
||||
len, cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t register_notification_rsp(btrc_event_id_t event_id,
|
||||
btrc_notification_type_t type,
|
||||
btrc_register_notification_t *p_param)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
switch (event_id) {
|
||||
case BTRC_EVT_PLAY_STATUS_CHANGED:
|
||||
return play_status_changed_rsp(type, &p_param->play_status);
|
||||
case BTRC_EVT_TRACK_CHANGE:
|
||||
return track_change_rsp(type, &p_param->track);
|
||||
case BTRC_EVT_TRACK_REACHED_END:
|
||||
return track_reached_end_rsp(type);
|
||||
case BTRC_EVT_TRACK_REACHED_START:
|
||||
return track_reached_start_rsp(type);
|
||||
case BTRC_EVT_PLAY_POS_CHANGED:
|
||||
return play_pos_changed_rsp(type, &p_param->song_pos);
|
||||
case BTRC_EVT_APP_SETTINGS_CHANGED:
|
||||
return settings_changed_rsp(type, &p_param->player_setting);
|
||||
default:
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static bt_status_t set_volume(uint8_t volume)
|
||||
{
|
||||
struct hal_cmd_avrcp_set_volume cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.value = volume;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_AVRCP, HAL_OP_AVRCP_SET_VOLUME,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct hal_cmd_unregister_module cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return;
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_AVRCP;
|
||||
|
||||
hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_AVRCP);
|
||||
|
||||
cbs = NULL;
|
||||
}
|
||||
|
||||
static btrc_interface_t iface = {
|
||||
.size = sizeof(iface),
|
||||
.init = init,
|
||||
.get_play_status_rsp = get_play_status_rsp,
|
||||
.list_player_app_attr_rsp = list_player_app_attr_rsp,
|
||||
.list_player_app_value_rsp = list_player_app_value_rsp,
|
||||
.get_player_app_value_rsp = get_player_app_value_rsp,
|
||||
.get_player_app_attr_text_rsp = get_player_app_attr_text_rsp,
|
||||
.get_player_app_value_text_rsp = get_player_app_value_text_rsp,
|
||||
.get_element_attr_rsp = get_element_attr_rsp,
|
||||
.set_player_app_value_rsp = set_player_app_value_rsp,
|
||||
.register_notification_rsp = register_notification_rsp,
|
||||
.set_volume = set_volume,
|
||||
.cleanup = cleanup
|
||||
};
|
||||
|
||||
btrc_interface_t *bt_get_avrcp_interface(void)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,642 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include "hal-log.h"
|
||||
#include "hal.h"
|
||||
#include "hal-msg.h"
|
||||
#include "ipc-common.h"
|
||||
#include "hal-ipc.h"
|
||||
|
||||
static const bthf_client_callbacks_t *cbs = NULL;
|
||||
|
||||
static bool interface_ready(void)
|
||||
{
|
||||
return cbs != NULL;
|
||||
}
|
||||
|
||||
static void handle_conn_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_conn_state *ev = buf;
|
||||
|
||||
if (cbs->connection_state_cb)
|
||||
cbs->connection_state_cb(ev->state, ev->peer_feat,
|
||||
ev->chld_feat,
|
||||
(bt_bdaddr_t *) ev->bdaddr);
|
||||
}
|
||||
|
||||
static void handle_audio_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_audio_state *ev = buf;
|
||||
|
||||
if (cbs->audio_state_cb)
|
||||
cbs->audio_state_cb(ev->state, (bt_bdaddr_t *) (ev->bdaddr));
|
||||
}
|
||||
|
||||
static void handle_vr_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_vr_state *ev = buf;
|
||||
|
||||
if (cbs->vr_cmd_cb)
|
||||
cbs->vr_cmd_cb(ev->state);
|
||||
}
|
||||
|
||||
static void handle_network_state(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_net_state *ev = buf;
|
||||
|
||||
if (cbs->network_state_cb)
|
||||
cbs->network_state_cb(ev->state);
|
||||
}
|
||||
|
||||
static void handle_network_roaming(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_net_roaming_type *ev = buf;
|
||||
|
||||
if (cbs->network_roaming_cb)
|
||||
cbs->network_roaming_cb(ev->state);
|
||||
}
|
||||
|
||||
static void handle_network_signal(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_net_signal_strength *ev = buf;
|
||||
|
||||
if (cbs->network_signal_cb)
|
||||
cbs->network_signal_cb(ev->signal_strength);
|
||||
}
|
||||
|
||||
static void handle_battery_level(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_battery_level *ev = buf;
|
||||
|
||||
if (cbs->battery_level_cb)
|
||||
cbs->battery_level_cb(ev->battery_level);
|
||||
}
|
||||
|
||||
static void handle_operator_name(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_operator_name *ev = buf;
|
||||
uint16_t name_len = ev->name_len;
|
||||
char *name = NULL;
|
||||
|
||||
if (len != sizeof(*ev) + name_len ||
|
||||
(name_len != 0 && ev->name[name_len - 1] != '\0')) {
|
||||
error("invalid operator name, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (name_len)
|
||||
name = (char *) ev->name;
|
||||
|
||||
if (cbs->current_operator_cb)
|
||||
cbs->current_operator_cb(name);
|
||||
}
|
||||
|
||||
static void handle_call(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_call_indicator *ev = buf;
|
||||
|
||||
if (cbs->call_cb)
|
||||
cbs->call_cb(ev->call);
|
||||
}
|
||||
|
||||
static void handle_call_setup(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_call_setup_indicator *ev = buf;
|
||||
|
||||
if (cbs->callsetup_cb)
|
||||
cbs->callsetup_cb(ev->call_setup);
|
||||
}
|
||||
|
||||
static void handle_call_held(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_call_held_indicator *ev = buf;
|
||||
|
||||
if (cbs->callheld_cb)
|
||||
cbs->callheld_cb(ev->call_held);
|
||||
}
|
||||
|
||||
static void handle_response_and_hold(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_response_and_hold_status *ev = buf;
|
||||
|
||||
if (cbs->resp_and_hold_cb)
|
||||
cbs->resp_and_hold_cb(ev->status);
|
||||
}
|
||||
|
||||
static void handle_clip(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_calling_line_ident *ev = buf;
|
||||
uint16_t num_len = ev->number_len;
|
||||
char *number = NULL;
|
||||
|
||||
if (len != sizeof(*ev) + num_len ||
|
||||
(num_len != 0 && ev->number[num_len - 1] != '\0')) {
|
||||
error("invalid clip, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (num_len)
|
||||
number = (char *) ev->number;
|
||||
|
||||
if (cbs->clip_cb)
|
||||
cbs->clip_cb(number);
|
||||
}
|
||||
|
||||
static void handle_call_waiting(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_call_waiting *ev = buf;
|
||||
uint16_t num_len = ev->number_len;
|
||||
char *number = NULL;
|
||||
|
||||
if (len != sizeof(*ev) + num_len ||
|
||||
(num_len != 0 && ev->number[num_len - 1] != '\0')) {
|
||||
error("invalid call waiting, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (num_len)
|
||||
number = (char *) ev->number;
|
||||
|
||||
if (cbs->call_waiting_cb)
|
||||
cbs->call_waiting_cb(number);
|
||||
}
|
||||
|
||||
static void handle_current_calls(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_current_call *ev = buf;
|
||||
uint16_t num_len = ev->number_len;
|
||||
char *number = NULL;
|
||||
|
||||
if (len != sizeof(*ev) + num_len ||
|
||||
(num_len != 0 && ev->number[num_len - 1] != '\0')) {
|
||||
error("invalid current calls, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (num_len)
|
||||
number = (char *) ev->number;
|
||||
|
||||
if (cbs->current_calls_cb)
|
||||
cbs->current_calls_cb(ev->index, ev->direction, ev->call_state,
|
||||
ev->multiparty, number);
|
||||
}
|
||||
|
||||
static void handle_volume_change(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_volume_changed *ev = buf;
|
||||
|
||||
if (cbs->volume_change_cb)
|
||||
cbs->volume_change_cb(ev->type, ev->volume);
|
||||
}
|
||||
|
||||
static void handle_command_cmp(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_command_complete *ev = buf;
|
||||
|
||||
if (cbs->cmd_complete_cb)
|
||||
cbs->cmd_complete_cb(ev->type, ev->cme);
|
||||
}
|
||||
|
||||
static void handle_subscriber_info(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
const struct hal_ev_hf_client_subscriber_service_info *ev = buf;
|
||||
uint16_t name_len = ev->name_len;
|
||||
char *name = NULL;
|
||||
|
||||
if (len != sizeof(*ev) + name_len ||
|
||||
(name_len != 0 && ev->name[name_len - 1] != '\0')) {
|
||||
error("invalid sunscriber info, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (name_len)
|
||||
name = (char *) ev->name;
|
||||
|
||||
if (cbs->subscriber_info_cb)
|
||||
cbs->subscriber_info_cb(name, ev->type);
|
||||
}
|
||||
|
||||
static void handle_in_band_ringtone(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
struct hal_ev_hf_client_inband_settings *ev = buf;
|
||||
|
||||
if (cbs->in_band_ring_tone_cb)
|
||||
cbs->in_band_ring_tone_cb(ev->state);
|
||||
}
|
||||
|
||||
static void handle_last_voice_tag_number(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
const struct hal_ev_hf_client_last_void_call_tag_num *ev = buf;
|
||||
char *number = NULL;
|
||||
uint16_t num_len = ev->number_len;
|
||||
|
||||
if (len != sizeof(*ev) + num_len ||
|
||||
(num_len != 0 && ev->number[num_len - 1] != '\0')) {
|
||||
error("invalid voice tag, aborting");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (num_len)
|
||||
number = (char *) ev->number;
|
||||
|
||||
if (cbs->last_voice_tag_number_callback)
|
||||
cbs->last_voice_tag_number_callback(number);
|
||||
}
|
||||
|
||||
static void handle_ring_indication(void *buf, uint16_t len, int fd)
|
||||
{
|
||||
if (cbs->ring_indication_cb)
|
||||
cbs->ring_indication_cb();
|
||||
}
|
||||
|
||||
/*
|
||||
* handlers will be called from notification thread context,
|
||||
* index in table equals to 'opcode - HAL_MINIMUM_EVENT'
|
||||
*/
|
||||
static const struct hal_ipc_handler ev_handlers[] = {
|
||||
/* HAL_EV_HF_CLIENT_CONN_STATE */
|
||||
{ handle_conn_state, false,
|
||||
sizeof(struct hal_ev_hf_client_conn_state) },
|
||||
/* HAL_EV_HF_CLIENT_AUDIO_STATE */
|
||||
{ handle_audio_state, false,
|
||||
sizeof(struct hal_ev_hf_client_audio_state) },
|
||||
/* HAL_EV_HF_CLIENT_VR_STATE */
|
||||
{ handle_vr_state, false, sizeof(struct hal_ev_hf_client_vr_state) },
|
||||
/*HAL_EV_HF_CLIENT_NET_STATE */
|
||||
{ handle_network_state, false,
|
||||
sizeof(struct hal_ev_hf_client_net_state)},
|
||||
/*HAL_EV_HF_CLIENT_NET_ROAMING_TYPE */
|
||||
{ handle_network_roaming, false,
|
||||
sizeof(struct hal_ev_hf_client_net_roaming_type) },
|
||||
/* HAL_EV_HF_CLIENT_NET_SIGNAL_STRENGTH */
|
||||
{ handle_network_signal, false,
|
||||
sizeof(struct hal_ev_hf_client_net_signal_strength) },
|
||||
/* HAL_EV_HF_CLIENT_BATTERY_LEVEL */
|
||||
{ handle_battery_level, false,
|
||||
sizeof(struct hal_ev_hf_client_battery_level) },
|
||||
/* HAL_EV_HF_CLIENT_OPERATOR_NAME */
|
||||
{ handle_operator_name, true,
|
||||
sizeof(struct hal_ev_hf_client_operator_name) },
|
||||
/* HAL_EV_HF_CLIENT_CALL_INDICATOR */
|
||||
{ handle_call, false,
|
||||
sizeof(struct hal_ev_hf_client_call_indicator) },
|
||||
/* HAL_EV_HF_CLIENT_CALL_SETUP_INDICATOR */
|
||||
{ handle_call_setup, false,
|
||||
sizeof(struct hal_ev_hf_client_call_setup_indicator) },
|
||||
/* HAL_EV_HF_CLIENT_CALL_HELD_INDICATOR */
|
||||
{ handle_call_held, false,
|
||||
sizeof(struct hal_ev_hf_client_call_held_indicator) },
|
||||
/* HAL_EV_HF_CLIENT_RESPONSE_AND_HOLD_STATUS */
|
||||
{ handle_response_and_hold, false,
|
||||
sizeof(struct hal_ev_hf_client_response_and_hold_status) },
|
||||
/* HAL_EV_HF_CLIENT_CALLING_LINE_IDENT */
|
||||
{ handle_clip, true,
|
||||
sizeof(struct hal_ev_hf_client_calling_line_ident) },
|
||||
/* HAL_EV_HF_CLIENT_CALL_WAITING */
|
||||
{ handle_call_waiting, true,
|
||||
sizeof(struct hal_ev_hf_client_call_waiting) },
|
||||
/* HAL_EV_HF_CLIENT_CURRENT_CALL */
|
||||
{ handle_current_calls, true,
|
||||
sizeof(struct hal_ev_hf_client_current_call) },
|
||||
/* HAL_EV_CLIENT_VOLUME_CHANGED */
|
||||
{ handle_volume_change, false,
|
||||
sizeof(struct hal_ev_hf_client_volume_changed) },
|
||||
/* HAL_EV_CLIENT_COMMAND_COMPLETE */
|
||||
{ handle_command_cmp, false,
|
||||
sizeof(struct hal_ev_hf_client_command_complete) },
|
||||
/* HAL_EV_CLIENT_SUBSCRIBER_SERVICE_INFO */
|
||||
{ handle_subscriber_info, true,
|
||||
sizeof(struct hal_ev_hf_client_subscriber_service_info) },
|
||||
/* HAL_EV_CLIENT_INBAND_SETTINGS */
|
||||
{ handle_in_band_ringtone, false,
|
||||
sizeof(struct hal_ev_hf_client_inband_settings) },
|
||||
/* HAL_EV_CLIENT_LAST_VOICE_CALL_TAG_NUM */
|
||||
{ handle_last_voice_tag_number, true,
|
||||
sizeof(struct hal_ev_hf_client_last_void_call_tag_num) },
|
||||
/* HAL_EV_CLIENT_RING_INDICATION */
|
||||
{ handle_ring_indication, false, 0 },
|
||||
};
|
||||
|
||||
static bt_status_t init(bthf_client_callbacks_t *callbacks)
|
||||
{
|
||||
struct hal_cmd_register_module cmd;
|
||||
int ret;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (interface_ready())
|
||||
return BT_STATUS_DONE;
|
||||
|
||||
cbs = callbacks;
|
||||
|
||||
hal_ipc_register(HAL_SERVICE_ID_HANDSFREE_CLIENT, ev_handlers,
|
||||
sizeof(ev_handlers)/sizeof(ev_handlers[0]));
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_HANDSFREE_CLIENT;
|
||||
cmd.mode = HAL_MODE_DEFAULT;
|
||||
cmd.max_clients = 1;
|
||||
|
||||
ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
cbs = NULL;
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE_CLIENT);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bt_status_t hf_client_connect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_hf_client_connect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (!bd_addr)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_CONNECT, sizeof(cmd), &cmd,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_hf_client_disconnect cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (!bd_addr)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_DISCONNECT, sizeof(cmd), &cmd,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t connect_audio(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_hf_client_connect_audio cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (!bd_addr)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_CONNECT_AUDIO, sizeof(cmd),
|
||||
&cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t disconnect_audio(bt_bdaddr_t *bd_addr)
|
||||
{
|
||||
struct hal_cmd_hf_client_disconnect_audio cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (!bd_addr)
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
|
||||
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_DISCONNECT_AUDIO, sizeof(cmd),
|
||||
&cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t start_voice_recognition(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_START_VR, 0, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bt_status_t stop_voice_recognition(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_STOP_VR, 0, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bt_status_t volume_control(bthf_client_volume_type_t type,
|
||||
int volume)
|
||||
{
|
||||
struct hal_cmd_hf_client_volume_control cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.type = type;
|
||||
cmd.volume = volume;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_VOLUME_CONTROL, sizeof(cmd),
|
||||
&cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t dial(const char *number)
|
||||
{
|
||||
char buf[IPC_MTU];
|
||||
struct hal_cmd_hf_client_dial *cmd = (void *) buf;
|
||||
size_t len;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
if (number) {
|
||||
cmd->number_len = strlen(number) + 1;
|
||||
memcpy(cmd->number, number, cmd->number_len);
|
||||
} else {
|
||||
cmd->number_len = 0;
|
||||
}
|
||||
|
||||
len = sizeof(*cmd) + cmd->number_len;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_DIAL, len, cmd, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bt_status_t dial_memory(int location)
|
||||
{
|
||||
struct hal_cmd_hf_client_dial_memory cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.location = location;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_DIAL_MEMORY,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t call_action(bthf_client_call_action_t action, int index)
|
||||
{
|
||||
struct hal_cmd_hf_client_call_action cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.action = action;
|
||||
cmd.index = index;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_CALL_ACTION, sizeof(cmd), &cmd,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t query_current_calls(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_QUERY_CURRENT_CALLS, 0, NULL,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t query_operator_name(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_QUERY_OPERATOR_NAME, 0, NULL,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t retrieve_subsr_info(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_RETRIEVE_SUBSCR_INFO, 0, NULL,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t send_dtmf(char tone)
|
||||
{
|
||||
struct hal_cmd_hf_client_send_dtmf cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
cmd.tone = tone;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_SEND_DTMF, sizeof(cmd), &cmd,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static bt_status_t request_last_voice_tag_number(void)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return BT_STATUS_NOT_READY;
|
||||
|
||||
return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE_CLIENT,
|
||||
HAL_OP_HF_CLIENT_GET_LAST_VOICE_TAG_NUM,
|
||||
0, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct hal_cmd_unregister_module cmd;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!interface_ready())
|
||||
return;
|
||||
|
||||
cmd.service_id = HAL_SERVICE_ID_HANDSFREE_CLIENT;
|
||||
|
||||
hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
|
||||
sizeof(cmd), &cmd, NULL, NULL, NULL);
|
||||
|
||||
hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE_CLIENT);
|
||||
|
||||
cbs = NULL;
|
||||
}
|
||||
|
||||
static bthf_client_interface_t iface = {
|
||||
.size = sizeof(iface),
|
||||
.init = init,
|
||||
.connect = hf_client_connect,
|
||||
.disconnect = disconnect,
|
||||
.connect_audio = connect_audio,
|
||||
.disconnect_audio = disconnect_audio,
|
||||
.start_voice_recognition = start_voice_recognition,
|
||||
.stop_voice_recognition = stop_voice_recognition,
|
||||
.volume_control = volume_control,
|
||||
.dial = dial,
|
||||
.dial_memory = dial_memory,
|
||||
.handle_call_action = call_action,
|
||||
.query_current_calls = query_current_calls,
|
||||
.query_current_operator_name = query_operator_name,
|
||||
.retrieve_subscriber_info = retrieve_subsr_info,
|
||||
.send_dtmf = send_dtmf,
|
||||
.request_last_voice_tag_number = request_last_voice_tag_number,
|
||||
.cleanup = cleanup
|
||||
};
|
||||
|
||||
bthf_client_interface_t *bt_get_hf_client_interface(void)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user