mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-02-16 22:05:31 -05:00
Add wireless status detection and monitoring functions
This commit is contained in:
parent
4564f76627
commit
9bde703969
1 changed files with 179 additions and 0 deletions
|
|
@ -276,6 +276,168 @@ static void unescape(const char *src, char *dst)
|
|||
*d = 0;
|
||||
}
|
||||
|
||||
static enum wireless_status read_wireless_status(const char *sysfs_path)
|
||||
{
|
||||
char buf[16];
|
||||
ssize_t sz;
|
||||
int fd;
|
||||
|
||||
fd = open(sysfs_path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return WIRELESS_STATUS_UNKNOWN;
|
||||
|
||||
sz = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
|
||||
if (sz <= 0)
|
||||
return WIRELESS_STATUS_UNKNOWN;
|
||||
|
||||
buf[sz] = '\0';
|
||||
if (buf[sz - 1] == '\n')
|
||||
buf[sz - 1] = '\0';
|
||||
|
||||
if (spa_streq(buf, "connected"))
|
||||
return WIRELESS_STATUS_CONNECTED;
|
||||
if (spa_streq(buf, "disconnected"))
|
||||
return WIRELESS_STATUS_DISCONNECTED;
|
||||
|
||||
return WIRELESS_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
static bool is_usb_interface_dir(const char *name)
|
||||
{
|
||||
const char *colon = strchr(name, ':');
|
||||
if (!colon || !strchr(name, '-'))
|
||||
return false;
|
||||
|
||||
for (const char *p = colon + 1; *p; p++)
|
||||
if (*p != '.' && !(*p >= '0' && *p <= '9'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *check_wireless_status_at_path(struct impl *this, const char *path)
|
||||
{
|
||||
char wireless_path[PATH_MAX];
|
||||
char *result;
|
||||
int res;
|
||||
|
||||
res = spa_scnprintf(wireless_path, sizeof(wireless_path),
|
||||
"%s/wireless_status", path);
|
||||
if (res < 0 || (size_t)res >= sizeof(wireless_path))
|
||||
return NULL;
|
||||
|
||||
if (access(wireless_path, R_OK) < 0)
|
||||
return NULL;
|
||||
|
||||
result = strdup(wireless_path);
|
||||
if (!result)
|
||||
spa_log_error(this->log, "failed to allocate wireless_status path");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *search_siblings_for_wireless_status(struct impl *this, const char *parent_path)
|
||||
{
|
||||
struct dirent *entry;
|
||||
char *result = NULL;
|
||||
int count = 0;
|
||||
|
||||
spa_autoptr(DIR) parent_dir = opendir(parent_path);
|
||||
if (!parent_dir)
|
||||
return NULL;
|
||||
|
||||
while ((entry = readdir(parent_dir)) != NULL) {
|
||||
char sibling_path[PATH_MAX];
|
||||
char *path;
|
||||
int res;
|
||||
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!is_usb_interface_dir(entry->d_name))
|
||||
continue;
|
||||
|
||||
if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
res = spa_scnprintf(sibling_path, sizeof(sibling_path),
|
||||
"%s/%s", parent_path, entry->d_name);
|
||||
if (res < 0 || (size_t)res >= sizeof(sibling_path))
|
||||
continue;
|
||||
|
||||
path = check_wireless_status_at_path(this, sibling_path);
|
||||
if (path) {
|
||||
count++;
|
||||
if (!result)
|
||||
result = path;
|
||||
else
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
spa_log_info(this->log, "found %d wireless_status files, using first one", count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *find_wireless_status_path(struct impl *this, const char *card_syspath)
|
||||
{
|
||||
char usb_device_path[PATH_MAX];
|
||||
char *last_slash, *result;
|
||||
int i, res;
|
||||
|
||||
res = spa_scnprintf(usb_device_path, sizeof(usb_device_path), "%s", card_syspath);
|
||||
if (res < 0 || (size_t)res >= sizeof(usb_device_path))
|
||||
return NULL;
|
||||
|
||||
result = check_wireless_status_at_path(this, usb_device_path);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
for (i = 0; i < MAX_PARENT_TRAVERSAL_DEPTH; i++) {
|
||||
last_slash = strrchr(usb_device_path, '/');
|
||||
if (!last_slash || last_slash == usb_device_path)
|
||||
break;
|
||||
|
||||
*last_slash = '\0';
|
||||
|
||||
result = search_siblings_for_wireless_status(this, usb_device_path);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void update_wireless_status(struct impl *this, struct card *card)
|
||||
{
|
||||
enum wireless_status status;
|
||||
bool disconnected;
|
||||
|
||||
if (!card->wireless_status_path)
|
||||
return;
|
||||
|
||||
status = read_wireless_status(card->wireless_status_path);
|
||||
|
||||
if (status == WIRELESS_STATUS_UNKNOWN) {
|
||||
spa_log_info(this->log, "card %u wireless_status unreadable, removing monitor",
|
||||
card->card_nr);
|
||||
free(card->wireless_status_path);
|
||||
card->wireless_status_path = NULL;
|
||||
card->wireless_disconnected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
disconnected = (status == WIRELESS_STATUS_DISCONNECTED);
|
||||
if (disconnected != card->wireless_disconnected) {
|
||||
spa_log_info(this->log, "card %u wireless device %s",
|
||||
card->card_nr, disconnected ? "disconnected" : "connected");
|
||||
card->wireless_disconnected = disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
static int check_device_pcm_class(const char *devname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
|
@ -906,6 +1068,23 @@ static int start_inotify(struct impl *this)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct card *find_card_by_wireless_status_path(struct impl *this, const char *syspath)
|
||||
{
|
||||
char wireless_path[PATH_MAX];
|
||||
int res;
|
||||
|
||||
res = spa_scnprintf(wireless_path, sizeof(wireless_path), "%s/wireless_status", syspath);
|
||||
if (res < 0 || (size_t)res >= sizeof(wireless_path))
|
||||
return NULL;
|
||||
|
||||
for (unsigned int i = 0; i < this->n_cards; i++) {
|
||||
if (this->cards[i].wireless_status_path &&
|
||||
spa_streq(this->cards[i].wireless_status_path, wireless_path))
|
||||
return &this->cards[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void impl_on_fd_events(struct spa_source *source)
|
||||
{
|
||||
struct impl *this = source->data;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue