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*)
27 calloc(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 int err;
50 cras_audio_thread_event_message_init(&msg, event_type);
51 err = cras_main_message_send(&msg.header);
52 if (err < 0) {
53 syslog(LOG_ERR, "Failed to send audio thread event message %d",
54 event_type);
55 return err;
56 }
57 return 0;
58 }
59
cras_audio_thread_debug()60 int cras_audio_thread_debug()
61 {
62 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_DEBUG);
63 }
64
cras_audio_thread_busyloop()65 int cras_audio_thread_busyloop()
66 {
67 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_BUSYLOOP);
68 }
69
cras_audio_thread_underrun()70 int cras_audio_thread_underrun()
71 {
72 return cras_audio_thread_event_send(AUDIO_THREAD_EVENT_UNDERRUN);
73 }
74
cras_audio_thread_severe_underrun()75 int cras_audio_thread_severe_underrun()
76 {
77 return cras_audio_thread_event_send(
78 AUDIO_THREAD_EVENT_SEVERE_UNDERRUN);
79 }
80
81 static struct timespec last_event_snapshot_time[AUDIO_THREAD_EVENT_TYPE_COUNT];
82
83 /*
84 * Callback function for handling audio thread events in main thread,
85 * which takes a snapshot of the audio thread and waits at least 30 seconds
86 * for the same event type. Events with the same event type within 30 seconds
87 * will be ignored by the handle function.
88 */
handle_audio_thread_event_message(struct cras_main_message * msg,void * arg)89 static void handle_audio_thread_event_message(
90 struct cras_main_message *msg,
91 void *arg) {
92 struct cras_audio_thread_event_message *audio_thread_msg =
93 (struct cras_audio_thread_event_message *)msg;
94 struct timespec now_time;
95
96 /*
97 * Skip invalid event types
98 */
99 if(audio_thread_msg->event_type >= AUDIO_THREAD_EVENT_TYPE_COUNT)
100 return;
101
102 struct timespec *last_snapshot_time =
103 &last_event_snapshot_time[audio_thread_msg->event_type];
104
105 clock_gettime(CLOCK_REALTIME, &now_time);
106
107 /*
108 * Wait at least 30 seconds for the same event type
109 */
110 struct timespec diff_time;
111 subtract_timespecs(&now_time, last_snapshot_time, &diff_time);
112 if((last_snapshot_time->tv_sec == 0 &&
113 last_snapshot_time->tv_nsec == 0) ||
114 diff_time.tv_sec >= MIN_WAIT_SECOND)
115 {
116 take_snapshot(audio_thread_msg->event_type);
117 *last_snapshot_time = now_time;
118 }
119 }
120
cras_audio_thread_monitor_init()121 int cras_audio_thread_monitor_init()
122 {
123 memset(last_event_snapshot_time,
124 0, sizeof(struct timespec) * AUDIO_THREAD_EVENT_TYPE_COUNT);
125 cras_main_message_add_handler(CRAS_MAIN_AUDIO_THREAD_EVENT,
126 handle_audio_thread_event_message, NULL);
127 return 0;
128 }
129