baac0febed8a0889088fbbc4787ed957b376b542
[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
40 static void sink_input_block(struct userdata *, pa_sink_input *, pa_bool_t);
41
42 pa_bool_t pa_stream_state_start_corked(struct userdata *u,
43                                        pa_sink_input_new_data *data,
44                                        pa_nodeset_resdef *resdef)
45 {
46     if (resdef) {
47         if (pa_streq(data->driver, scache_driver)) {
48             pa_assert((data->flags & flag_mask) == flag_mask);
49         }
50
51         data->flags &= ~flag_mask;
52         data->flags |= PA_SINK_INPUT_START_CORKED;
53
54         return TRUE;
55     }
56
57     return FALSE;
58 }
59
60 void pa_stream_state_change(struct userdata *u, mir_node *node, int req)
61 {
62     pa_loopnode *loop;
63     uint32_t idx;
64     pa_sink_input *sinp;
65     pa_source_output *sout;
66     pa_core *core;
67
68     pa_assert(u);
69     pa_assert(node);
70
71     pa_assert_se((core = u->core));
72
73     loop = node->loop;
74
75     pa_assert((!loop && node->implement == mir_stream) ||
76               ( loop && node->implement == mir_device)   );
77     pa_assert(node->direction == mir_input || node->direction == mir_output);
78
79     if (loop) {
80         if (node->direction == mir_input) {
81             sinp = pa_idxset_get_by_index(core->sink_inputs,
82                                           loop->sink_input_index);
83             pa_assert(sinp);
84
85             switch (req) {
86             case PA_STREAM_KILL:
87             case PA_STREAM_BLOCK:
88                 pa_log_debug("mute '%s'", node->amname);
89                 pa_sink_input_set_mute(sinp, TRUE, FALSE);
90                 break;
91                 
92             case PA_STREAM_RUN:
93                 pa_log_debug("unmute '%s'", node->amname);
94                 pa_sink_input_set_mute(sinp, FALSE, FALSE);
95                 break;
96                 
97             default:
98                 pa_assert_not_reached();
99                 break;
100             }
101         }
102         else {
103             pa_log_debug("no enforcement for loopback on '%s'", node->amname);
104             sout = pa_idxset_get_by_index(core->source_outputs,
105                                           loop->source_output_index);
106             pa_assert(sout);
107         }
108     }
109     else {
110         if (node->direction == mir_input) {
111             sinp = pa_idxset_get_by_index(core->sink_inputs, node->paidx);
112             pa_assert(sinp);
113
114             switch (req) {
115             case PA_STREAM_KILL:
116                 pa_log_debug("killing '%s'", node->amname);
117                 sinp->kill(sinp);
118                 break;
119                 
120             case PA_STREAM_BLOCK:
121                 pa_log_debug("blocking '%s'", node->amname);
122                 sink_input_block(u, sinp, TRUE);
123                 break;
124                 
125             case PA_STREAM_RUN:
126                 pa_log_debug("unblock '%s'", node->amname);
127                 sink_input_block(u, sinp, FALSE);
128                 break;
129                 
130             default:
131                 pa_assert_not_reached();
132                 break;
133             }
134         }
135         else {
136             pa_log_debug("no enforcement for stream '%s'", node->amname);
137             sout = pa_idxset_get_by_index(core->source_outputs, node->paidx);
138             pa_assert(sout);
139         }
140     }
141 }
142
143
144 static void sink_input_block(struct userdata *u,
145                              pa_sink_input *sinp,
146                              pa_bool_t block)
147 {
148     const char *event;
149     pa_proplist *pl;
150     bool block_by_mute;
151     bool muted, corked;
152     pa_volume_t oldvol;
153
154     pa_assert(sinp);
155
156     if (sinp->driver && pa_streq(sinp->driver, scache_driver)) {
157         if (block)
158             sinp->flags &= ~flag_mask;
159         else
160             sinp->flags |= flag_mask;
161     }
162
163     muted = pa_sink_input_get_mute(sinp);
164     corked = (sinp->flags & PA_SINK_INPUT_START_CORKED);
165
166     if (corked && !block)
167         sinp->flags &= ~PA_SINK_INPUT_START_CORKED;
168
169     block_by_mute = !corked;
170
171     pa_log_debug("%sblock by %s", block ? "":"un",
172                  block_by_mute ? "muting":"corking");
173
174     if (block_by_mute) {
175         if ((muted && !block) || (!muted && block)) {
176             if (!block) {
177                 oldvol = pa_fader_get_volume(u, sinp);
178
179                 pa_log_debug("fading in to %u", oldvol);
180
181                 pa_fader_set_volume(u, sinp, 0);
182                 pa_fader_ramp_volume(u, sinp, oldvol);
183             }
184
185             pa_sink_input_set_mute(sinp, block, FALSE);
186         }
187     }
188     else {
189         if ((corked && !block) || (!corked &&  block)) {
190             pa_sink_input_cork_internal(sinp, block);
191
192             if (sinp->send_event) {
193                 if (block)
194                     event = PA_STREAM_EVENT_REQUEST_CORK;
195                 else
196                     event = PA_STREAM_EVENT_REQUEST_UNCORK;
197                 
198                 pl = pa_proplist_new();
199                 
200                 sinp->send_event(sinp, event, pl);
201                 
202                 pa_proplist_free(pl);
203             }
204         }
205     }
206 }
207
208 /*
209  * Local Variables:
210  * c-basic-offset: 4
211  * indent-tabs-mode: nil
212  * End:
213  *
214  */