1 /* Copyright (c) 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 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 = cras_tm_create_timer(list->timer_manager, 44 MAX(max_drain_delay, 10), delete_streams, list); 45 } 46 47 /* 48 * Exported Interface 49 */ 50 51 struct stream_list *stream_list_create(stream_callback *add_cb, 52 stream_callback *rm_cb, 53 stream_create_func *create_cb, 54 stream_destroy_func *destroy_cb, 55 struct cras_tm *timer_manager) 56 { 57 struct stream_list *list = calloc(1, sizeof(struct stream_list)); 58 59 list->stream_added_cb = add_cb; 60 list->stream_removed_cb = rm_cb; 61 list->stream_create_cb = create_cb; 62 list->stream_destroy_cb = destroy_cb; 63 list->timer_manager = timer_manager; 64 return list; 65 } 66 67 void stream_list_destroy(struct stream_list *list) 68 { 69 free(list); 70 } 71 72 struct cras_rstream *stream_list_get(struct stream_list *list) 73 { 74 return list->streams; 75 } 76 77 int stream_list_add(struct stream_list *list, 78 struct cras_rstream_config *stream_config, 79 struct cras_rstream **stream) 80 { 81 int rc; 82 83 rc = list->stream_create_cb(stream_config, stream); 84 if (rc) 85 return rc; 86 87 DL_APPEND(list->streams, *stream); 88 rc = list->stream_added_cb(*stream); 89 if (rc) { 90 DL_DELETE(list->streams, *stream); 91 list->stream_destroy_cb(*stream); 92 } 93 94 return rc; 95 } 96 97 int stream_list_rm(struct stream_list *list, cras_stream_id_t id) 98 { 99 struct cras_rstream *to_remove; 100 101 DL_SEARCH_SCALAR(list->streams, to_remove, stream_id, id); 102 if (!to_remove) 103 return -EINVAL; 104 DL_DELETE(list->streams, to_remove); 105 DL_APPEND(list->streams_to_delete, to_remove); 106 if (list->drain_timer) { 107 cras_tm_cancel_timer(list->timer_manager, list->drain_timer); 108 list->drain_timer = NULL; 109 } 110 delete_streams(NULL, list); 111 112 return 0; 113 } 114 115 int stream_list_rm_all_client_streams(struct stream_list *list, 116 struct cras_rclient *rclient) 117 { 118 struct cras_rstream *to_remove; 119 int rc = 0; 120 121 DL_FOREACH(list->streams, to_remove) { 122 if (to_remove->client == rclient) { 123 DL_DELETE(list->streams, to_remove); 124 DL_APPEND(list->streams_to_delete, to_remove); 125 } 126 } 127 if (list->drain_timer) { 128 cras_tm_cancel_timer(list->timer_manager, list->drain_timer); 129 list->drain_timer = NULL; 130 } 131 delete_streams(NULL, list); 132 133 return rc; 134 135 } 136 137