/* 
 | 
 * 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 
 |