Home | History | Annotate | Download | only in server
      1 /* Copyright 2016 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <syslog.h>
      7 
      8 #include "cras_device_monitor.h"
      9 #include "cras_iodev_list.h"
     10 #include "cras_main_message.h"
     11 
     12 enum CRAS_DEVICE_MONITOR_MSG_TYPE {
     13 	RESET_DEVICE,
     14 	SET_MUTE_STATE,
     15 };
     16 
     17 struct cras_device_monitor_message {
     18 	struct cras_main_message header;
     19 	enum CRAS_DEVICE_MONITOR_MSG_TYPE message_type;
     20 	struct cras_iodev *iodev;
     21 };
     22 
     23 static void init_device_msg(
     24 		struct cras_device_monitor_message *msg,
     25 		enum CRAS_DEVICE_MONITOR_MSG_TYPE type,
     26 		struct cras_iodev *iodev)
     27 {
     28 	memset(msg, 0, sizeof(*msg));
     29 	msg->header.type = CRAS_MAIN_MONITOR_DEVICE;
     30 	msg->header.length = sizeof(*msg);
     31 	msg->message_type = type;
     32 	msg->iodev = iodev;
     33 }
     34 
     35 int cras_device_monitor_reset_device(struct cras_iodev *iodev)
     36 {
     37 	struct cras_device_monitor_message msg;
     38 	int err;
     39 
     40 	init_device_msg(&msg, RESET_DEVICE, iodev);
     41 	err = cras_main_message_send((struct cras_main_message *)&msg);
     42 	if (err < 0) {
     43 		syslog(LOG_ERR, "Failed to send device message %d",
     44 		       RESET_DEVICE);
     45 		return err;
     46 	}
     47 	return 0;
     48 }
     49 
     50 int cras_device_monitor_set_device_mute_state(struct cras_iodev *iodev)
     51 {
     52 	struct cras_device_monitor_message msg;
     53 	int err;
     54 
     55 	init_device_msg(&msg, SET_MUTE_STATE, iodev);
     56 	err = cras_main_message_send((struct cras_main_message *)&msg);
     57 	if (err < 0) {
     58 		syslog(LOG_ERR, "Failed to send device message %d",
     59 		       SET_MUTE_STATE);
     60 		return err;
     61 	}
     62 	return 0;
     63 }
     64 
     65 
     66 /* When device is in a bad state, e.g. severe underrun,
     67  * it might break how audio thread works and cause busy wake up loop.
     68  * Resetting the device can bring device back to normal state.
     69  * Let main thread follow the disable/enable sequence in iodev_list
     70  * to properly close/open the device while enabling/disabling fallback
     71  * device.
     72  */
     73 static void handle_device_message(struct cras_main_message *msg, void *arg)
     74 {
     75 	struct cras_device_monitor_message *device_msg =
     76 			(struct cras_device_monitor_message *)msg;
     77 	struct cras_iodev *iodev = device_msg->iodev;
     78 
     79 	switch (device_msg->message_type) {
     80 	case RESET_DEVICE:
     81 		syslog(LOG_ERR, "trying to recover device 0x%x by resetting it",
     82 		       iodev->info.idx);
     83 		cras_iodev_list_disable_dev(iodev);
     84 		cras_iodev_list_enable_dev(iodev);
     85 		break;
     86 	case SET_MUTE_STATE:
     87 		cras_iodev_set_mute(iodev);
     88 		break;
     89 	default:
     90 		syslog(LOG_ERR, "Unknown device message type %u",
     91 		       device_msg->message_type);
     92 		break;
     93 	}
     94 }
     95 
     96 int cras_device_monitor_init()
     97 {
     98 	cras_main_message_add_handler(CRAS_MAIN_MONITOR_DEVICE,
     99 				      handle_device_message, NULL);
    100 	return 0;
    101 }
    102