source: mainline/uspace/srv/audio/hound/connection.c

Last change on this file was 2fbd49c, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Audio synk needs locking

Without locking the list of sink connections, we are exposed
to a race between removing a connection at the end of playback
(typically while destroying a hound context) and audio device
event PCM_EVENT_FRAMES_PLAYED which causes audio mixing to occur
via audio_sink_mix_inputs(), causing hound to crash often at
the end of playback.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2013 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup audio
30 * @brief HelenOS sound server
31 * @{
32 */
33/** @file
34 */
35
36#include <errno.h>
37#include <stdlib.h>
38
39#include "log.h"
40#include "connection.h"
41
42/**
43 * Create connection between source and sink.
44 * @param source Valid source structure.
45 * @param sink Valid sink structure.
46 * @return pointer to a valid connection structure, NULL on failure.
47 *
48 * Reports new connection to both the source and sink.
49 */
50connection_t *connection_create(audio_source_t *source, audio_sink_t *sink)
51{
52 assert(source);
53 assert(sink);
54 connection_t *conn = malloc(sizeof(connection_t));
55 if (conn) {
56 audio_pipe_init(&conn->fifo);
57 link_initialize(&conn->source_link);
58 link_initialize(&conn->sink_link);
59 link_initialize(&conn->hound_link);
60 conn->sink = sink;
61 conn->source = source;
62 list_append(&conn->source_link, &source->connections);
63 fibril_mutex_lock(&sink->lock);
64 list_append(&conn->sink_link, &sink->connections);
65 fibril_mutex_unlock(&sink->lock);
66 audio_sink_set_format(sink, audio_source_format(source));
67 if (source->connection_change)
68 source->connection_change(source, true);
69 if (sink->connection_change)
70 sink->connection_change(sink, true);
71 log_debug("CONNECTED: %s -> %s", source->name, sink->name);
72 }
73 return conn;
74}
75
76/**
77 * Destroy existing connection
78 * @param connection The connection to destroy.
79 *
80 * Disconnects from both the source and the sink.
81 */
82void connection_destroy(connection_t *connection)
83{
84 assert(connection);
85 assert(!link_in_use(&connection->hound_link));
86 list_remove(&connection->source_link);
87 fibril_mutex_lock(&connection->sink->lock);
88 list_remove(&connection->sink_link);
89 fibril_mutex_unlock(&connection->sink->lock);
90 if (connection->sink && connection->sink->connection_change)
91 connection->sink->connection_change(connection->sink, false);
92 if (connection->source && connection->source->connection_change)
93 connection->source->connection_change(connection->source, false);
94 audio_pipe_fini(&connection->fifo);
95 log_debug("DISCONNECTED: %s -> %s",
96 connection->source->name, connection->sink->name);
97 free(connection);
98}
99
100/**
101 * Update and mix data provided by the source.
102 * @param connection the connection to add.
103 * @param data Destination audio buffer.
104 * @param size size of the destination audio buffer.
105 * @param format format of the destination audio buffer.
106 */
107errno_t connection_add_source_data(connection_t *connection, void *data,
108 size_t size, pcm_format_t format)
109{
110 assert(connection);
111 if (!data)
112 return EBADMEM;
113 const size_t needed_frames = pcm_format_size_to_frames(size, &format);
114 if (needed_frames > audio_pipe_frames(&connection->fifo) &&
115 connection->source->update_available_data) {
116 log_debug("Asking source to provide more data");
117 connection->source->update_available_data(
118 connection->source, size);
119 }
120 log_verbose("Data available after update: %zu",
121 audio_pipe_bytes(&connection->fifo));
122 size_t ret =
123 audio_pipe_mix_data(&connection->fifo, data, size, &format);
124 if (ret != size)
125 log_warning("Connection failed to provide enough data %zd/%zu",
126 ret, size);
127 return EOK;
128}
129/**
130 * Add new data to the connection buffer.
131 * @param connection Target conneciton.
132 * @aparam adata Reference counted audio data buffer.
133 * @return Error code.
134 */
135errno_t connection_push_data(connection_t *connection,
136 audio_data_t *adata)
137{
138 assert(connection);
139 assert(adata);
140 const errno_t ret = audio_pipe_push(&connection->fifo, adata);
141 if (ret == EOK && connection->sink->data_available)
142 connection->sink->data_available(connection->sink);
143 return ret;
144}
145
146/**
147 * @}
148 */
Note: See TracBrowser for help on using the repository browser.