linuxOS_AP05/external/bluez-alsa/src/transport.h
2025-06-02 13:59:07 +08:00

282 lines
7.2 KiB
C

/*
* BlueALSA - transport.h
* Copyright (c) 2016-2018 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
* This project is licensed under the terms of the MIT license.
*
*/
#ifndef BLUEALSA_TRANSPORT_H_
#define BLUEALSA_TRANSPORT_H_
#include <pthread.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <glib.h>
#include "bluez.h"
#include "hfp.h"
enum ba_transport_type {
TRANSPORT_TYPE_A2DP,
TRANSPORT_TYPE_RFCOMM,
TRANSPORT_TYPE_SCO,
};
enum ba_transport_state {
TRANSPORT_IDLE,
TRANSPORT_PENDING,
TRANSPORT_ACTIVE,
TRANSPORT_PAUSED,
/* transport is in the eviction state */
TRANSPORT_LIMBO,
};
enum ba_transport_signal {
TRANSPORT_PCM_OPEN,
TRANSPORT_PCM_CLOSE,
TRANSPORT_PCM_PAUSE,
TRANSPORT_PCM_RESUME,
TRANSPORT_PCM_SYNC,
TRANSPORT_SET_VOLUME,
TRANSPORT_SEND_RFCOMM,
};
struct ba_device {
/* ID of the underlying HCI device */
int hci_dev_id;
/* address of the Bluetooth device */
bdaddr_t addr;
/* human-readable Bluetooth device name */
char name[HCI_MAX_NAME_LENGTH];
/* adjusted (in the range 0-100) battery level */
struct {
bool enabled;
uint8_t level;
} battery;
/* Apple's extension used with HFP profile */
struct {
uint16_t vendor_id;
uint16_t product_id;
uint16_t version;
uint8_t features;
/* determine whether headset is docked */
uint8_t accev_docked;
} xapl;
/* hash-map with connected transports */
GHashTable *transports;
};
struct ba_pcm {
int fd;
/* client identifier (most likely client socket file descriptor) used
* by the PCM client lookup function - transport_lookup_pcm_client() */
int client;
/* variables used for PCM synchronization */
pthread_cond_t drained;
pthread_mutex_t drained_mn;
};
struct ba_transport {
/* backward reference to the owner */
struct ba_device *device;
/* Transport structure covers all transports supported by BlueALSA. However,
* every transport requires specific handling - link acquisition, transport
* specific configuration, freeing resources, etc. */
enum ba_transport_type type;
/* data required for D-Bus management */
char *dbus_owner;
char *dbus_path;
/* Selected profile and audio codec. For A2DP vendor codecs the upper byte
* of the codec field contains the lowest byte of the vendor ID. */
enum bluetooth_profile profile;
uint16_t codec;
/* This mutex shall guard modifications of the critical sections in this
* transport structure, e.g. thread creation/termination. */
pthread_mutex_t mutex;
/* IO thread - actual transport layer */
enum ba_transport_state state;
pthread_t thread;
/* This field stores a file descriptor (socket) associated with the BlueZ
* side of the transport. The role of this socket depends on the transport
* type - it can be either A2DP, RFCOMM or SCO link. */
int bt_fd;
/* max transfer unit values for bt_fd */
size_t mtu_read;
size_t mtu_write;
/* PIPE used to notify thread about changes. If thread is based on loop with
* an event wait syscall (e.g. poll), this file descriptor is used to send a
* control event. */
int sig_fd[2];
/* Overall delay in 1/10 of millisecond, caused by the data transfer and
* the audio encoder or decoder. */
unsigned int delay;
union {
struct {
/* if non-zero, equivalent of volume = 0 */
uint8_t ch1_muted;
uint8_t ch2_muted;
/* software audio volume in range [0, 127] */
uint8_t ch1_volume;
uint8_t ch2_volume;
/* delay reported by the AVDTP */
uint16_t delay;
struct ba_pcm pcm;
/* selected audio codec configuration */
uint8_t *cconfig;
size_t cconfig_size;
/* Value reported by the ioctl(TIOCOUTQ) when the output buffer is
* empty. Somehow this ioctl call reports "available" buffer space.
* So, in order to get the number of bytes in the queue buffer, we
* have to subtract the initial value from values returned by
* subsequent ioctl() calls. */
int bt_fd_coutq_init;
} a2dp;
struct {
/* associated SCO transport */
struct ba_transport *sco;
/* AG/HF supported features bitmask */
uint32_t hfp_features;
/* received AG indicator values */
unsigned char hfp_inds[__HFP_IND_MAX];
} rfcomm;
struct {
/* parent RFCOMM transport */
struct ba_transport *rfcomm;
/* if true, equivalent of gain = 0 */
bool spk_muted;
bool mic_muted;
/* software audio gain in range [0, 15] */
uint8_t spk_gain;
uint8_t mic_gain;
/* Speaker and microphone signals should to be exposed as
* a separate PCM devices. Hence, there is a requirement
* for separate configurations. */
struct ba_pcm spk_pcm;
struct ba_pcm mic_pcm;
int listen_fd;
} sco;
};
/* indicates cleanup lock */
bool cleanup_lock;
/* callback function for self-management */
int (*release)(struct ba_transport *);
};
struct ba_device *device_new(int hci_dev_id, const bdaddr_t *addr, const char *name);
void device_free(struct ba_device *d);
struct ba_device *device_get(GHashTable *devices, const char *key);
struct ba_device *device_lookup(GHashTable *devices, const char *key);
bool device_remove(GHashTable *devices, const char *key);
void device_set_battery_level(struct ba_device *d, uint8_t value);
struct ba_transport *transport_new(
struct ba_device *device,
enum ba_transport_type type,
const char *dbus_owner,
const char *dbus_path,
enum bluetooth_profile profile,
uint16_t codec);
struct ba_transport *transport_new_a2dp(
struct ba_device *device,
const char *dbus_owner,
const char *dbus_path,
enum bluetooth_profile profile,
uint16_t codec,
const uint8_t *config,
size_t config_size);
struct ba_transport *transport_new_rfcomm(
struct ba_device *device,
const char *dbus_owner,
const char *dbus_path,
enum bluetooth_profile profile);
void transport_free(struct ba_transport *t);
struct ba_transport *transport_lookup(GHashTable *devices, const char *dbus_path);
struct ba_transport *transport_lookup_pcm_client(GHashTable *devices, int client);
bool transport_remove(GHashTable *devices, const char *dbus_path);
int transport_send_signal(struct ba_transport *t, enum ba_transport_signal sig);
int transport_send_rfcomm(struct ba_transport *t, const char command[32]);
unsigned int transport_get_channels(const struct ba_transport *t);
unsigned int transport_get_sampling(const struct ba_transport *t);
int transport_set_volume(struct ba_transport *t, uint8_t ch1_muted, uint8_t ch2_muted,
uint8_t ch1_volume, uint8_t ch2_volume);
int transport_set_state(struct ba_transport *t, enum ba_transport_state state);
int transport_set_state_from_string(struct ba_transport *t, const char *state);
int transport_drain_pcm(struct ba_transport *t);
int transport_acquire_bt_a2dp(struct ba_transport *t);
int transport_release_bt_a2dp(struct ba_transport *t);
int transport_release_bt_rfcomm(struct ba_transport *t);
int transport_acquire_bt_sco(struct ba_transport *t);
int transport_acquire_bt_sco2(struct ba_transport *t, int asock);
int transport_release_bt_sco(struct ba_transport *t);
int transport_release_pcm(struct ba_pcm *pcm);
void transport_pthread_cancel(pthread_t thread);
void transport_pthread_cleanup(struct ba_transport *t);
int transport_pthread_cleanup_lock(struct ba_transport *t);
int transport_pthread_cleanup_unlock(struct ba_transport *t);
#endif