/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "cras_rstream.h" #include "cras_tm.h" #include "cras_types.h" #include "stream_list.h" #include "utlist.h" struct stream_list { struct cras_rstream *streams; struct cras_rstream *streams_to_delete; stream_callback *stream_added_cb; stream_callback *stream_removed_cb; stream_create_func *stream_create_cb; stream_destroy_func *stream_destroy_cb; struct cras_tm *timer_manager; struct cras_timer *drain_timer; }; static void delete_streams(struct cras_timer *timer, void *data) { struct cras_rstream *to_delete; struct stream_list *list = (struct stream_list *)data; int max_drain_delay = 0; DL_FOREACH(list->streams_to_delete, to_delete) { int drain_delay; drain_delay = list->stream_removed_cb(to_delete); if (drain_delay) { max_drain_delay = MAX(max_drain_delay, drain_delay); continue; } DL_DELETE(list->streams_to_delete, to_delete); list->stream_destroy_cb(to_delete); } list->drain_timer = NULL; if (max_drain_delay) list->drain_timer = cras_tm_create_timer(list->timer_manager, MAX(max_drain_delay, 10), delete_streams, list); } /* * Exported Interface */ struct stream_list *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) { struct stream_list *list = calloc(1, sizeof(struct stream_list)); list->stream_added_cb = add_cb; list->stream_removed_cb = rm_cb; list->stream_create_cb = create_cb; list->stream_destroy_cb = destroy_cb; list->timer_manager = timer_manager; return list; } void stream_list_destroy(struct stream_list *list) { free(list); } struct cras_rstream *stream_list_get(struct stream_list *list) { return list->streams; } int stream_list_add(struct stream_list *list, struct cras_rstream_config *stream_config, struct cras_rstream **stream) { int rc; rc = list->stream_create_cb(stream_config, stream); if (rc) return rc; DL_APPEND(list->streams, *stream); rc = list->stream_added_cb(*stream); if (rc) { DL_DELETE(list->streams, *stream); list->stream_destroy_cb(*stream); } return rc; } int stream_list_rm(struct stream_list *list, cras_stream_id_t id) { struct cras_rstream *to_remove; DL_SEARCH_SCALAR(list->streams, to_remove, stream_id, id); if (!to_remove) return -EINVAL; DL_DELETE(list->streams, to_remove); DL_APPEND(list->streams_to_delete, to_remove); if (list->drain_timer) { cras_tm_cancel_timer(list->timer_manager, list->drain_timer); list->drain_timer = NULL; } delete_streams(NULL, list); return 0; } int stream_list_rm_all_client_streams(struct stream_list *list, struct cras_rclient *rclient) { struct cras_rstream *to_remove; int rc = 0; DL_FOREACH(list->streams, to_remove) { if (to_remove->client == rclient) { DL_DELETE(list->streams, to_remove); DL_APPEND(list->streams_to_delete, to_remove); } } if (list->drain_timer) { cras_tm_cancel_timer(list->timer_manager, list->drain_timer); list->drain_timer = NULL; } delete_streams(NULL, list); return rc; }