c87b78c716aea23bd3054becbdee65d4ad8aec7d
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / stream-state.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <pulsecore/pulsecore-config.h>
26 #include <pulsecore/sink-input.h>
27 #include <pulsecore/source-output.h>
28 #include <pulsecore/core-util.h>
29
30 #include "stream-state.h"
31 #include "node.h"
32 #include "loopback.h"
33 #include "fader.h"
34
35 static const char *scache_driver = "play-memblockq.c";
36 static pa_sink_input_flags_t flag_mask = PA_SINK_INPUT_NO_CREATE_ON_SUSPEND |
37                                          PA_SINK_INPUT_KILL_ON_SUSPEND;
38
39 static void sink_input_block(struct userdata *, pa_sink_input *, bool);
40
41 bool pa_stream_state_start_corked(struct userdata *u,
42                                        pa_sink_input_new_data *data,
43                                        pa_nodeset_resdef *resdef)
44 {
45     if (resdef) {
46         if (pa_streq(data->driver, scache_driver)) {
47             pa_assert((data->flags & flag_mask) == flag_mask);
48         }
49
50         data->flags &= ~flag_mask;
51         data->flags |= PA_SINK_INPUT_START_CORKED;
52
53         return true;
54     }
55
56     return false;
57 }
58
59 void pa_stream_state_change(struct userdata *u, mir_node *node, int req)
60 {
61     pa_loopnode *loop;
62     uint32_t idx;
63     pa_sink_input *sinp;
64     pa_source_output *sout;
65     pa_core *core;
66
67     pa_assert(u);
68     pa_assert(node);
69
70     pa_assert_se((core = u->core));
71
72     loop = node->loop;
73
74     pa_assert((!loop && node->implement == mir_stream) ||
75               ( loop && node->implement == mir_device)   );
76     pa_assert(node->direction == mir_input || node->direction == mir_output);
77
78     if (loop) {
79         if (node->direction == mir_input) {
80             sinp = pa_idxset_get_by_index(core->sink_inputs,
81                                           loop->sink_input_index);
82             pa_assert(sinp);
83
84             switch (req) {
85             case PA_STREAM_KILL:
86             case PA_STREAM_BLOCK:
87                 pa_log_debug("mute '%s'", node->amname);
88                 pa_sink_input_set_mute(sinp, true, false);
89                 break;
90                 
91             case PA_STREAM_RUN:
92                 pa_log_debug("unmute '%s'", node->amname);
93                 pa_sink_input_set_mute(sinp, false, false);
94                 break;
95                 
96             default:
97                 pa_assert_not_reached();
98                 break;
99             }
100         }
101         else {
102             pa_log_debug("no enforcement for loopback on '%s'", node->amname);
103             sout = pa_idxset_get_by_index(core->source_outputs,
104                                           loop->source_output_index);
105             pa_assert(sout);
106         }
107     }
108     else {
109         if (node->direction == mir_input) {
110             sinp = pa_idxset_get_by_index(core->sink_inputs, node->paidx);
111             pa_assert(sinp);
112
113             switch (req) {
114             case PA_STREAM_KILL:
115                 pa_log_debug("killing '%s'", node->amname);
116                 sinp->kill(sinp);
117                 break;
118                 
119             case PA_STREAM_BLOCK:
120                 pa_log_debug("blocking '%s'", node->amname);
121                 sink_input_block(u, sinp, true);
122                 break;
123                 
124             case PA_STREAM_RUN:
125                 pa_log_debug("unblock '%s'", node->amname);
126                 sink_input_block(u, sinp, false);
127                 break;
128                 
129             default:
130                 pa_assert_not_reached();
131                 break;
132             }
133         }
134         else {
135             pa_log_debug("no enforcement for stream '%s'", node->amname);
136             sout = pa_idxset_get_by_index(core->source_outputs, node->paidx);
137             pa_assert(sout);
138         }
139     }
140 }
141
142
143 static void sink_input_block(struct userdata *u,
144                              pa_sink_input *sinp,
145                              bool block)
146 {
147     const char *event;
148     pa_proplist *pl;
149     bool block_by_mute;
150     bool muted, corked;
151     pa_volume_t oldvol;
152
153     pa_assert(sinp);
154
155     if (sinp->driver && pa_streq(sinp->driver, scache_driver)) {
156         if (block)
157             sinp->flags &= ~flag_mask;
158         else
159             sinp->flags |= flag_mask;
160     }
161
162     muted = pa_sink_input_get_mute(sinp);
163     corked = (sinp->flags & PA_SINK_INPUT_START_CORKED);
164
165     if (corked && !block)
166         sinp->flags &= ~PA_SINK_INPUT_START_CORKED;
167
168     block_by_mute = !corked;
169
170     pa_log_debug("%sblock by %s", block ? "":"un",
171                  block_by_mute ? "muting":"corking");
172
173     if (block_by_mute) {
174         if ((muted && !block) || (!muted && block)) {
175             if (!block) {
176                 oldvol = pa_fader_get_volume(u, sinp);
177
178                 pa_log_debug("fading in to %u", oldvol);
179
180                 pa_fader_set_volume(u, sinp, 0);
181                 pa_fader_ramp_volume(u, sinp, oldvol);
182             }
183
184             pa_sink_input_set_mute(sinp, block, FALSE);
185         }
186     }
187     else {
188         if ((corked && !block) || (!corked &&  block)) {
189             pa_sink_input_cork_internal(sinp, block);
190
191             if (sinp->send_event) {
192                 if (block)
193                     event = PA_STREAM_EVENT_REQUEST_CORK;
194                 else
195                     event = PA_STREAM_EVENT_REQUEST_UNCORK;
196                 
197                 pl = pa_proplist_new();
198                 
199                 sinp->send_event(sinp, event, pl);
200                 
201                 pa_proplist_free(pl);
202             }
203         }
204     }
205 }
206
207 /*
208  * Local Variables:
209  * c-basic-offset: 4
210  * indent-tabs-mode: nil
211  * End:
212  *
213  */