• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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