1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 #include <gmerlin/log.h>
27 #define LOG_DOMAIN "player.audio"
28
29 #include <gmerlin/player.h>
30 #include <playerprivate.h>
31
bg_player_audio_create(bg_player_t * p,bg_plugin_registry_t * plugin_reg)32 void bg_player_audio_create(bg_player_t * p, bg_plugin_registry_t * plugin_reg)
33 {
34 bg_player_audio_stream_t * s = &p->audio_stream;
35
36 bg_gavl_audio_options_init(&s->options);
37
38 s->th = bg_player_thread_create(p->thread_common);
39
40 s->fc =
41 bg_audio_filter_chain_create(&s->options,
42 plugin_reg);
43
44 s->cnv_out = gavl_audio_converter_create();
45
46 s->volume = gavl_volume_control_create();
47 s->peak_detector = gavl_peak_detector_create();
48
49 pthread_mutex_init(&s->volume_mutex,NULL);
50 pthread_mutex_init(&s->config_mutex,NULL);
51 pthread_mutex_init(&s->time_mutex,NULL);
52 pthread_mutex_init(&s->mute_mutex, NULL);
53 pthread_mutex_init(&s->eof_mutex,NULL);
54
55 s->timer = gavl_timer_create();
56 }
57
bg_player_audio_destroy(bg_player_t * p)58 void bg_player_audio_destroy(bg_player_t * p)
59 {
60 bg_player_audio_stream_t * s = &p->audio_stream;
61 gavl_audio_converter_destroy(s->cnv_out);
62 bg_gavl_audio_options_free(&s->options);
63 bg_audio_filter_chain_destroy(s->fc);
64
65 gavl_volume_control_destroy(s->volume);
66 gavl_peak_detector_destroy(s->peak_detector);
67 pthread_mutex_destroy(&s->volume_mutex);
68 pthread_mutex_destroy(&s->eof_mutex);
69
70 pthread_mutex_destroy(&s->time_mutex);
71 gavl_timer_destroy(s->timer);
72
73 if(s->plugin_handle)
74 bg_plugin_unref(s->plugin_handle);
75
76 bg_player_thread_destroy(s->th);
77
78 }
79
bg_player_audio_init(bg_player_t * player,int audio_stream)80 int bg_player_audio_init(bg_player_t * player, int audio_stream)
81 {
82 gavl_sample_format_t force_format;
83 gavl_audio_options_t * opt;
84 bg_player_audio_stream_t * s;
85 // int do_filter;
86
87 if(!DO_AUDIO(player->flags))
88 return 1;
89
90 s = &player->audio_stream;
91 s->send_silence = 0;
92
93 s->options.options_changed = 0;
94
95 s->in_func = bg_player_input_read_audio;
96 s->in_data = player;
97 s->in_stream = player->current_audio_stream;
98
99 bg_player_input_get_audio_format(player);
100
101 bg_audio_filter_chain_connect_input(s->fc,
102 s->in_func,
103 s->in_data,
104 s->in_stream);
105 s->in_func = bg_audio_filter_chain_read;
106 s->in_data = s->fc;
107 s->in_stream = 0;
108
109 pthread_mutex_lock(&s->config_mutex);
110 force_format = s->options.force_format;
111 bg_audio_filter_chain_init(s->fc, &s->input_format, &s->fifo_format);
112 pthread_mutex_unlock(&s->config_mutex);
113
114
115 gavl_audio_format_copy(&s->output_format,
116 &s->fifo_format);
117
118 if(!bg_player_oa_init(s))
119 return 0;
120
121 gavl_audio_format_copy(&s->fifo_format,
122 &s->output_format);
123
124 if(force_format != GAVL_SAMPLE_NONE)
125 s->fifo_format.sample_format = force_format;
126
127 bg_audio_filter_chain_set_out_format(s->fc, &s->fifo_format);
128
129 /* Volume control */
130 gavl_volume_control_set_format(s->volume,
131 &s->fifo_format);
132 gavl_peak_detector_set_format(s->peak_detector,
133 &s->fifo_format);
134
135 /* Output conversion */
136 opt = gavl_audio_converter_get_options(s->cnv_out);
137 gavl_audio_options_copy(opt, s->options.opt);
138
139 s->fifo_frame = gavl_audio_frame_create(&s->output_format);
140
141 if(!gavl_audio_converter_init(s->cnv_out,
142 &s->fifo_format,
143 &s->output_format))
144 {
145 s->do_convert_out = 0;
146 s->output_frame = s->fifo_frame;
147 }
148 else
149 {
150 s->do_convert_out = 1;
151 s->output_frame =
152 gavl_audio_frame_create(&s->output_format);
153 }
154 return 1;
155 }
156
bg_player_audio_cleanup(bg_player_t * player)157 void bg_player_audio_cleanup(bg_player_t * player)
158 {
159 bg_player_audio_stream_t * s;
160 s = &player->audio_stream;
161
162 if(s->fifo_frame)
163 {
164 gavl_audio_frame_destroy(s->fifo_frame);
165 s->fifo_frame = NULL;
166 }
167 if(s->output_frame && s->do_convert_out)
168 {
169 gavl_audio_frame_destroy(s->output_frame);
170 }
171 s->output_frame = NULL;
172 }
173
174 /* Configuration stuff */
175
176 static const bg_parameter_info_t parameters[] =
177 {
178 #if 0
179 {
180 .name = "audio",
181 .long_name = TRS("Audio"),
182 .type = BG_PARAMETER_SECTION,
183 },
184 #endif
185 BG_GAVL_PARAM_FORCE_SAMPLEFORMAT,
186 BG_GAVL_PARAM_CONVERSION_QUALITY,
187 BG_GAVL_PARAM_AUDIO_DITHER_MODE,
188 BG_GAVL_PARAM_SAMPLERATE,
189 BG_GAVL_PARAM_RESAMPLE_MODE,
190 BG_GAVL_PARAM_CHANNEL_SETUP,
191 { /* End of parameters */ }
192 };
193
194
195
bg_player_get_audio_parameters(bg_player_t * p)196 const bg_parameter_info_t * bg_player_get_audio_parameters(bg_player_t * p)
197 {
198 return parameters;
199 }
200
bg_player_get_audio_filter_parameters(bg_player_t * p)201 const bg_parameter_info_t * bg_player_get_audio_filter_parameters(bg_player_t * p)
202 {
203 return bg_audio_filter_chain_get_parameters(p->audio_stream.fc);
204 }
205
206
bg_player_set_audio_parameter(void * data,const char * name,const bg_parameter_value_t * val)207 void bg_player_set_audio_parameter(void * data, const char * name,
208 const bg_parameter_value_t * val)
209 {
210 bg_player_t * p = (bg_player_t*)data;
211 int need_restart = 0;
212 int is_interrupted;
213 int do_init;
214 int check_restart;
215
216 do_init = (bg_player_get_state(p) == BG_PLAYER_STATE_INIT);
217
218 pthread_mutex_lock(&p->audio_stream.config_mutex);
219
220 is_interrupted = p->audio_stream.interrupted;
221
222 bg_gavl_audio_set_parameter(&p->audio_stream.options,
223 name, val);
224
225 if(!do_init && !is_interrupted)
226 check_restart = 1;
227 else
228 check_restart = 0;
229
230 if(check_restart)
231 need_restart = p->audio_stream.options.options_changed;
232
233 pthread_mutex_unlock(&p->audio_stream.config_mutex);
234
235 if(!need_restart && check_restart)
236 {
237 bg_audio_filter_chain_lock(p->audio_stream.fc);
238 need_restart =
239 bg_audio_filter_chain_need_restart(p->audio_stream.fc);
240 bg_audio_filter_chain_unlock(p->audio_stream.fc);
241 }
242
243 if(need_restart)
244 {
245 bg_log(BG_LOG_INFO, LOG_DOMAIN,
246 "Restarting playback due to changed audio options");
247 bg_player_interrupt(p);
248
249 pthread_mutex_lock(&p->audio_stream.config_mutex);
250 p->audio_stream.interrupted = 1;
251 pthread_mutex_unlock(&p->audio_stream.config_mutex);
252 }
253
254 if(!name && is_interrupted)
255 {
256 bg_player_interrupt_resume(p);
257 pthread_mutex_lock(&p->audio_stream.config_mutex);
258 p->audio_stream.interrupted = 0;
259 pthread_mutex_unlock(&p->audio_stream.config_mutex);
260 }
261 }
262
bg_player_set_audio_filter_parameter(void * data,const char * name,const bg_parameter_value_t * val)263 void bg_player_set_audio_filter_parameter(void * data, const char * name,
264 const bg_parameter_value_t * val)
265 {
266 int need_restart = 0;
267 int is_interrupted;
268 int do_init;
269 bg_player_t * p = (bg_player_t*)data;
270
271 do_init = (bg_player_get_state(p) == BG_PLAYER_STATE_INIT);
272
273 pthread_mutex_lock(&p->audio_stream.config_mutex);
274 is_interrupted = p->audio_stream.interrupted;
275 pthread_mutex_unlock(&p->audio_stream.config_mutex);
276
277 bg_audio_filter_chain_lock(p->audio_stream.fc);
278 bg_audio_filter_chain_set_parameter(p->audio_stream.fc, name, val);
279
280 need_restart =
281 bg_audio_filter_chain_need_restart(p->audio_stream.fc);
282
283 bg_audio_filter_chain_unlock(p->audio_stream.fc);
284
285 if(!do_init && need_restart && !is_interrupted)
286 {
287 bg_log(BG_LOG_INFO, LOG_DOMAIN,
288 "Restarting playback due to changed audio filters");
289 bg_player_interrupt(p);
290
291 pthread_mutex_lock(&p->audio_stream.config_mutex);
292 p->audio_stream.interrupted = 1;
293 pthread_mutex_unlock(&p->audio_stream.config_mutex);
294 }
295
296 if(!name && is_interrupted)
297 {
298 bg_player_interrupt_resume(p);
299 pthread_mutex_lock(&p->audio_stream.config_mutex);
300 p->audio_stream.interrupted = 0;
301 pthread_mutex_unlock(&p->audio_stream.config_mutex);
302 }
303
304
305 }
306
307 int
bg_player_read_audio(bg_player_t * p,gavl_audio_frame_t * frame)308 bg_player_read_audio(bg_player_t * p, gavl_audio_frame_t * frame)
309 {
310 bg_player_audio_stream_t * s = &p->audio_stream;
311 return s->in_func(s->in_data, frame, s->in_stream,
312 s->fifo_format.samples_per_frame);
313 }
314
bg_player_audio_set_eof(bg_player_t * p)315 int bg_player_audio_set_eof(bg_player_t * p)
316 {
317 bg_msg_t * msg;
318 int ret = 1;
319
320 bg_log(BG_LOG_INFO, LOG_DOMAIN, "Detected EOF");
321 pthread_mutex_lock(&p->video_stream.eof_mutex);
322 pthread_mutex_lock(&p->audio_stream.eof_mutex);
323
324 p->audio_stream.eof = 1;
325
326 if(p->video_stream.eof)
327 {
328 msg = bg_msg_queue_lock_write(p->command_queue);
329 bg_msg_set_id(msg, BG_PLAYER_CMD_SETSTATE);
330 bg_msg_set_arg_int(msg, 0, BG_PLAYER_STATE_EOF);
331 bg_msg_queue_unlock_write(p->command_queue);
332 }
333 else
334 {
335 ret = 0;
336 p->audio_stream.send_silence = 1;
337 }
338 pthread_mutex_unlock(&p->audio_stream.eof_mutex);
339 pthread_mutex_unlock(&p->video_stream.eof_mutex);
340 return ret;
341 }
342