1 /* Copyright 2018 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 <stdbool.h>
7 #include <syslog.h>
8 #include "audio_thread.h"
9 #include "cras_iodev_list.h"
10 #include "cras_main_message.h"
11 #include "cras_system_state.h"
12 #include "cras_types.h"
13 #include "cras_util.h"
14
15 #define MIN_WAIT_SECOND 30
16
17 struct cras_audio_thread_event_message {
18 struct cras_main_message header;
19 enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type;
20 };
21
take_snapshot(enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)22 static void take_snapshot(enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)
23 {
24 struct cras_audio_thread_snapshot *snapshot;
25
26 snapshot = (struct cras_audio_thread_snapshot *)calloc(
27 1, sizeof(struct cras_audio_thread_snapshot));
28 struct timespec now_time;
29 clock_gettime(CLOCK_MONOTONIC_RAW, &now_time);
30 snapshot->timestamp = now_time;
31 snapshot->event_type = event_type;
32 audio_thread_dump_thread_info(cras_iodev_list_get_audio_thread(),
33 &snapshot->audio_debug_info);
34 cras_system_state_add_snapshot(snapshot);
35 }
36
cras_audio_thread_event_message_init(struct cras_audio_thread_event_message * msg,enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)37 static void cras_audio_thread_event_message_init(
38 struct cras_audio_thread_event_message *msg,
39 enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)
40 {
41 msg->header.type = CRAS_MAIN_AUDIO_THREAD_EVENT;
42 msg->header.length = sizeof(*msg);
43 msg->event_type = event_type;
44 }
45
cras_audio_thread_event_send(enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)46 int cras_audio_thread_event_send(enum CRAS_AUDIO_THREAD_EVENT_TYPE event_type)
47 {
48 struct cras_audio_thread_event_message msg;
49 cras_audio_thread_event_message_init(&msg, event_type);
50 return cras_main_message_send(&msg.header);
51 }
52
cras_audio_thread_event_a2dp_overrun()53 int cras_audio_thread_event_a2dp_overrun()
54 {
55 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_A2DP_OVERRUN);
56 }
57
cras_audio_thread_event_a2dp_throttle()58 int cras_audio_thread_event_a2dp_throttle()
59 {
60 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_A2DP_THROTTLE);
61 }
62
cras_audio_thread_event_debug()63 int cras_audio_thread_event_debug()
64 {
65 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_DEBUG);
66 }
67
cras_audio_thread_event_busyloop()68 int cras_audio_thread_event_busyloop()
69 {
70 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_BUSYLOOP);
71 }
72
cras_audio_thread_event_underrun()73 int cras_audio_thread_event_underrun()
74 {
75 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_UNDERRUN);
76 }
77
cras_audio_thread_event_severe_underrun()78 int cras_audio_thread_event_severe_underrun()
79 {
80 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_SEVERE_UNDERRUN);
81 }
82
cras_audio_thread_event_drop_samples()83 int cras_audio_thread_event_drop_samples()
84 {
85 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_DROP_SAMPLES);
86 }
87
cras_audio_thread_event_dev_overrun()88 int cras_audio_thread_event_dev_overrun()
89 {
90 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_DEV_OVERRUN);
91 }
92
93 static struct timespec last_event_snapshot_time[AUDIO_THREAD_EVENT_TYPE_COUNT];
94
95 /*
96 * Callback function for handling audio thread events in main thread,
97 * which takes a snapshot of the audio thread and waits at least 30 seconds
98 * for the same event type. Events with the same event type within 30 seconds
99 * will be ignored by the handle function.
100 */
handle_audio_thread_event_message(struct cras_main_message * msg,void * arg)101 static void handle_audio_thread_event_message(struct cras_main_message *msg,
102 void *arg)
103 {
104 struct cras_audio_thread_event_message *audio_thread_msg =
105 (struct cras_audio_thread_event_message *)msg;
106 struct timespec now_time;
107
108 /*
109 * Skip invalid event types
110 */
111 if (audio_thread_msg->event_type >= AUDIO_THREAD_EVENT_TYPE_COUNT)
112 return;
113
114 struct timespec *last_snapshot_time =
115 &last_event_snapshot_time[audio_thread_msg->event_type];
116
117 clock_gettime(CLOCK_REALTIME, &now_time);
118
119 /*
120 * Wait at least 30 seconds for the same event type
121 */
122 struct timespec diff_time;
123 subtract_timespecs(&now_time, last_snapshot_time, &diff_time);
124 if ((last_snapshot_time->tv_sec == 0 &&
125 last_snapshot_time->tv_nsec == 0) ||
126 diff_time.tv_sec >= MIN_WAIT_SECOND) {
127 take_snapshot(audio_thread_msg->event_type);
128 *last_snapshot_time = now_time;
129 }
130 }
131
cras_audio_thread_monitor_init()132 int cras_audio_thread_monitor_init()
133 {
134 memset(last_event_snapshot_time, 0,
135 sizeof(struct timespec) * AUDIO_THREAD_EVENT_TYPE_COUNT);
136 cras_main_message_add_handler(CRAS_MAIN_AUDIO_THREAD_EVENT,
137 handle_audio_thread_event_message, NULL);
138 return 0;
139 }
140