• 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 "cras_rstream.h"
7 #include "cras_tm.h"
8 #include "cras_types.h"
9 #include "stream_list.h"
10 #include "utlist.h"
11 
12 struct stream_list {
13 	struct cras_rstream *streams;
14 	struct cras_rstream *streams_to_delete;
15 	stream_callback *stream_added_cb;
16 	stream_callback *stream_removed_cb;
17 	stream_create_func *stream_create_cb;
18 	stream_destroy_func *stream_destroy_cb;
19 	struct cras_tm *timer_manager;
20 	struct cras_timer *drain_timer;
21 };
22 
delete_streams(struct cras_timer * timer,void * data)23 static void delete_streams(struct cras_timer *timer, void *data)
24 {
25 	struct cras_rstream *to_delete;
26 	struct stream_list *list = (struct stream_list *)data;
27 	int max_drain_delay = 0;
28 
29 	DL_FOREACH (list->streams_to_delete, to_delete) {
30 		int drain_delay;
31 
32 		drain_delay = list->stream_removed_cb(to_delete);
33 		if (drain_delay) {
34 			max_drain_delay = MAX(max_drain_delay, drain_delay);
35 			continue;
36 		}
37 		DL_DELETE(list->streams_to_delete, to_delete);
38 		list->stream_destroy_cb(to_delete);
39 	}
40 
41 	list->drain_timer = NULL;
42 	if (max_drain_delay)
43 		list->drain_timer =
44 			cras_tm_create_timer(list->timer_manager,
45 					     MAX(max_drain_delay, 10),
46 					     delete_streams, list);
47 }
48 
49 /*
50  * Exported Interface
51  */
52 
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)53 struct stream_list *stream_list_create(stream_callback *add_cb,
54 				       stream_callback *rm_cb,
55 				       stream_create_func *create_cb,
56 				       stream_destroy_func *destroy_cb,
57 				       struct cras_tm *timer_manager)
58 {
59 	struct stream_list *list = calloc(1, sizeof(struct stream_list));
60 
61 	list->stream_added_cb = add_cb;
62 	list->stream_removed_cb = rm_cb;
63 	list->stream_create_cb = create_cb;
64 	list->stream_destroy_cb = destroy_cb;
65 	list->timer_manager = timer_manager;
66 	return list;
67 }
68 
stream_list_destroy(struct stream_list * list)69 void stream_list_destroy(struct stream_list *list)
70 {
71 	free(list);
72 }
73 
stream_list_get(struct stream_list * list)74 struct cras_rstream *stream_list_get(struct stream_list *list)
75 {
76 	return list->streams;
77 }
78 
stream_list_add(struct stream_list * list,struct cras_rstream_config * stream_config,struct cras_rstream ** stream)79 int stream_list_add(struct stream_list *list,
80 		    struct cras_rstream_config *stream_config,
81 		    struct cras_rstream **stream)
82 {
83 	int rc;
84 
85 	rc = list->stream_create_cb(stream_config, stream);
86 	if (rc)
87 		return rc;
88 
89 	DL_APPEND(list->streams, *stream);
90 	rc = list->stream_added_cb(*stream);
91 	if (rc) {
92 		DL_DELETE(list->streams, *stream);
93 		list->stream_destroy_cb(*stream);
94 	}
95 
96 	return rc;
97 }
98 
stream_list_rm(struct stream_list * list,cras_stream_id_t id)99 int stream_list_rm(struct stream_list *list, cras_stream_id_t id)
100 {
101 	struct cras_rstream *to_remove;
102 
103 	DL_SEARCH_SCALAR(list->streams, to_remove, stream_id, id);
104 	if (!to_remove)
105 		return -EINVAL;
106 	DL_DELETE(list->streams, to_remove);
107 	DL_APPEND(list->streams_to_delete, to_remove);
108 	if (list->drain_timer) {
109 		cras_tm_cancel_timer(list->timer_manager, list->drain_timer);
110 		list->drain_timer = NULL;
111 	}
112 	delete_streams(NULL, list);
113 
114 	return 0;
115 }
116 
stream_list_rm_all_client_streams(struct stream_list * list,struct cras_rclient * rclient)117 int stream_list_rm_all_client_streams(struct stream_list *list,
118 				      struct cras_rclient *rclient)
119 {
120 	struct cras_rstream *to_remove;
121 	int rc = 0;
122 
123 	DL_FOREACH (list->streams, to_remove) {
124 		if (to_remove->client == rclient) {
125 			DL_DELETE(list->streams, to_remove);
126 			DL_APPEND(list->streams_to_delete, to_remove);
127 		}
128 	}
129 	if (list->drain_timer) {
130 		cras_tm_cancel_timer(list->timer_manager, list->drain_timer);
131 		list->drain_timer = NULL;
132 	}
133 	delete_streams(NULL, list);
134 
135 	return rc;
136 }
137 
stream_list_has_pinned_stream(struct stream_list * list,unsigned int dev_idx)138 bool stream_list_has_pinned_stream(struct stream_list *list,
139 				   unsigned int dev_idx)
140 {
141 	struct cras_rstream *rstream;
142 	DL_FOREACH (list->streams, rstream) {
143 		if (!rstream->is_pinned)
144 			continue;
145 		if (rstream->pinned_dev_idx == dev_idx)
146 			return true;
147 	}
148 	return false;
149 }
150