• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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 #include "cras_rstream.h"
8 #include "cras_tm.h"
9 #include "cras_types.h"
10 #include "stream_list.h"
11 #include "utlist.h"
12 
13 /*
14  * If the time difference of two streams is short than 10s, they may be the RTC
15  * streams.
16  */
17 static const struct timespec RTC_STREAM_THRESHOLD = { 10, 0 };
18 
19 struct stream_list {
20 	struct cras_rstream *streams;
21 	struct cras_rstream *streams_to_delete;
22 	stream_callback *stream_added_cb;
23 	stream_callback *stream_removed_cb;
24 	stream_create_func *stream_create_cb;
25 	stream_destroy_func *stream_destroy_cb;
26 	struct cras_tm *timer_manager;
27 	struct cras_timer *drain_timer;
28 };
29 
delete_streams(struct cras_timer * timer,void * data)30 static void delete_streams(struct cras_timer *timer, void *data)
31 {
32 	struct cras_rstream *to_delete;
33 	struct stream_list *list = (struct stream_list *)data;
34 	int max_drain_delay = 0;
35 
36 	DL_FOREACH (list->streams_to_delete, to_delete) {
37 		int drain_delay;
38 
39 		drain_delay = list->stream_removed_cb(to_delete);
40 		if (drain_delay) {
41 			max_drain_delay = MAX(max_drain_delay, drain_delay);
42 			continue;
43 		}
44 		DL_DELETE(list->streams_to_delete, to_delete);
45 		list->stream_destroy_cb(to_delete);
46 	}
47 
48 	list->drain_timer = NULL;
49 	if (max_drain_delay)
50 		list->drain_timer =
51 			cras_tm_create_timer(list->timer_manager,
52 					     MAX(max_drain_delay, 10),
53 					     delete_streams, list);
54 }
55 
56 /*
57  * Exported Interface
58  */
59 
stream_list_create(stream_callback * add_cb,stream_callback * rm_cb,stream_create_func * create_cb,stream_destroy_func * destroy_cb,struct cras_tm * timer_manager)60 struct stream_list *stream_list_create(stream_callback *add_cb,
61 				       stream_callback *rm_cb,
62 				       stream_create_func *create_cb,
63 				       stream_destroy_func *destroy_cb,
64 				       struct cras_tm *timer_manager)
65 {
66 	struct stream_list *list = calloc(1, sizeof(struct stream_list));
67 
68 	list->stream_added_cb = add_cb;
69 	list->stream_removed_cb = rm_cb;
70 	list->stream_create_cb = create_cb;
71 	list->stream_destroy_cb = destroy_cb;
72 	list->timer_manager = timer_manager;
73 	return list;
74 }
75 
stream_list_destroy(struct stream_list * list)76 void stream_list_destroy(struct stream_list *list)
77 {
78 	free(list);
79 }
80 
stream_list_get(struct stream_list * list)81 struct cras_rstream *stream_list_get(struct stream_list *list)
82 {
83 	return list->streams;
84 }
85 
stream_list_add(struct stream_list * list,struct cras_rstream_config * stream_config,struct cras_rstream ** stream)86 int stream_list_add(struct stream_list *list,
87 		    struct cras_rstream_config *stream_config,
88 		    struct cras_rstream **stream)
89 {
90 	int rc;
91 	struct cras_rstream *next_stream;
92 
93 	rc = list->stream_create_cb(stream_config, stream);
94 	if (rc)
95 		return rc;
96 
97 	/* Keep stream list in descending order by channel count. */
98 	DL_FOREACH (list->streams, next_stream) {
99 		if ((*stream)->format.num_channels >=
100 		    next_stream->format.num_channels)
101 			break;
102 	}
103 	DL_INSERT(list->streams, next_stream, *stream);
104 	rc = list->stream_added_cb(*stream);
105 	if (rc) {
106 		DL_DELETE(list->streams, *stream);
107 		list->stream_destroy_cb(*stream);
108 	}
109 
110 	return rc;
111 }
112 
stream_list_rm(struct stream_list * list,cras_stream_id_t id)113 int stream_list_rm(struct stream_list *list, cras_stream_id_t id)
114 {
115 	struct cras_rstream *to_remove;
116 
117 	DL_SEARCH_SCALAR(list->streams, to_remove, stream_id, id);
118 	if (!to_remove)
119 		return -EINVAL;
120 	DL_DELETE(list->streams, to_remove);
121 	DL_APPEND(list->streams_to_delete, to_remove);
122 	if (list->drain_timer) {
123 		cras_tm_cancel_timer(list->timer_manager, list->drain_timer);
124 		list->drain_timer = NULL;
125 	}
126 	delete_streams(NULL, list);
127 
128 	return 0;
129 }
130 
stream_list_rm_all_client_streams(struct stream_list * list,struct cras_rclient * rclient)131 int stream_list_rm_all_client_streams(struct stream_list *list,
132 				      struct cras_rclient *rclient)
133 {
134 	struct cras_rstream *to_remove;
135 	int rc = 0;
136 
137 	DL_FOREACH (list->streams, to_remove) {
138 		if (to_remove->client == rclient) {
139 			DL_DELETE(list->streams, to_remove);
140 			DL_APPEND(list->streams_to_delete, to_remove);
141 		}
142 	}
143 	if (list->drain_timer) {
144 		cras_tm_cancel_timer(list->timer_manager, list->drain_timer);
145 		list->drain_timer = NULL;
146 	}
147 	delete_streams(NULL, list);
148 
149 	return rc;
150 }
151 
stream_list_has_pinned_stream(struct stream_list * list,unsigned int dev_idx)152 bool stream_list_has_pinned_stream(struct stream_list *list,
153 				   unsigned int dev_idx)
154 {
155 	struct cras_rstream *rstream;
156 	DL_FOREACH (list->streams, rstream) {
157 		if (!rstream->is_pinned)
158 			continue;
159 		if (rstream->pinned_dev_idx == dev_idx)
160 			return true;
161 	}
162 	return false;
163 }
164 
detect_rtc_stream_pair(struct stream_list * list,struct cras_rstream * stream)165 void detect_rtc_stream_pair(struct stream_list *list,
166 			    struct cras_rstream *stream)
167 {
168 	struct cras_rstream *next_stream;
169 	if (stream->cb_threshold != 480)
170 		return;
171 	if (stream->client_type != CRAS_CLIENT_TYPE_CHROME &&
172 	    stream->client_type != CRAS_CLIENT_TYPE_LACROS)
173 		return;
174 	DL_FOREACH (list->streams, next_stream) {
175 		if (next_stream->cb_threshold == 480 &&
176 		    next_stream->direction != stream->direction &&
177 		    next_stream->client_type == stream->client_type &&
178 		    timespec_diff_shorter_than(&stream->start_ts,
179 					       &next_stream->start_ts,
180 					       &RTC_STREAM_THRESHOLD)) {
181 			stream->stream_type =
182 				CRAS_STREAM_TYPE_VOICE_COMMUNICATION;
183 			next_stream->stream_type =
184 				CRAS_STREAM_TYPE_VOICE_COMMUNICATION;
185 			return;
186 		}
187 	}
188 }
189