summaryrefslogtreecommitdiff
path: root/cras/src/server/cras_device_monitor.c
blob: e9730a0be21fe44e92e7b59e12ae68de724e9096 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* 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 <stdbool.h>
#include <syslog.h>

#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;
}