/* Copyright 2016 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include "cras_device_monitor.h" #include "cras_iodev_list.h" #include "cras_main_message.h" enum CRAS_DEVICE_MONITOR_MSG_TYPE { RESET_DEVICE, SET_MUTE_STATE, ERROR_CLOSE, }; struct cras_device_monitor_message { struct cras_main_message header; enum CRAS_DEVICE_MONITOR_MSG_TYPE message_type; unsigned int dev_idx; }; static void init_device_msg(struct cras_device_monitor_message *msg, enum CRAS_DEVICE_MONITOR_MSG_TYPE type, unsigned int dev_idx) { memset(msg, 0, sizeof(*msg)); msg->header.type = CRAS_MAIN_MONITOR_DEVICE; msg->header.length = sizeof(*msg); msg->message_type = type; msg->dev_idx = dev_idx; } int cras_device_monitor_reset_device(unsigned int dev_idx) { struct cras_device_monitor_message msg; int err; init_device_msg(&msg, RESET_DEVICE, dev_idx); err = cras_main_message_send((struct cras_main_message *)&msg); if (err < 0) { syslog(LOG_ERR, "Failed to send device message %d", RESET_DEVICE); return err; } return 0; } int cras_device_monitor_set_device_mute_state(unsigned int dev_idx) { struct cras_device_monitor_message msg; int err; init_device_msg(&msg, SET_MUTE_STATE, dev_idx); err = cras_main_message_send((struct cras_main_message *)&msg); if (err < 0) { syslog(LOG_ERR, "Failed to send device message %d", SET_MUTE_STATE); return err; } return 0; } int cras_device_monitor_error_close(unsigned int dev_idx) { struct cras_device_monitor_message msg; int err; init_device_msg(&msg, ERROR_CLOSE, dev_idx); err = cras_main_message_send((struct cras_main_message *)&msg); if (err < 0) { syslog(LOG_ERR, "Failed to send device message %d", ERROR_CLOSE); return err; } return 0; } /* When device is in a bad state, e.g. severe underrun, * it might break how audio thread works and cause busy wake up loop. * Resetting the device can bring device back to normal state. * Let main thread follow the disable/enable sequence in iodev_list * to properly close/open the device while enabling/disabling fallback * device. */ static void handle_device_message(struct cras_main_message *msg, void *arg) { struct cras_device_monitor_message *device_msg = (struct cras_device_monitor_message *)msg; switch (device_msg->message_type) { case RESET_DEVICE: syslog(LOG_ERR, "trying to recover device 0x%x by resetting it", device_msg->dev_idx); cras_iodev_list_suspend_dev(device_msg->dev_idx); cras_iodev_list_resume_dev(device_msg->dev_idx); break; case SET_MUTE_STATE: cras_iodev_list_set_dev_mute(device_msg->dev_idx); break; case ERROR_CLOSE: syslog(LOG_ERR, "Close erroneous device in main thread"); cras_iodev_list_suspend_dev(device_msg->dev_idx); break; default: syslog(LOG_ERR, "Unknown device message type %u", device_msg->message_type); break; } } int cras_device_monitor_init() { cras_main_message_add_handler(CRAS_MAIN_MONITOR_DEVICE, handle_device_message, NULL); return 0; }