2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "output_api.h"
22 #include "encoder_plugin.h"
23 #include "encoder_list.h"
25 #include <shout/shout.h>
33 #define G_LOG_DOMAIN "shout"
35 #define DEFAULT_CONN_TIMEOUT 2
38 unsigned char data
[32768];
44 shout_metadata_t
*shout_meta
;
46 struct encoder
*encoder
;
53 struct shout_buffer buf
;
56 static int shout_init_count
;
59 * The quark used for GError.domain.
62 shout_output_quark(void)
64 return g_quark_from_static_string("shout_output");
67 static const struct encoder_plugin
*
68 shout_encoder_plugin_get(const char *name
)
70 if (strcmp(name
, "ogg") == 0)
72 else if (strcmp(name
, "mp3") == 0)
75 return encoder_plugin_get(name
);
78 static struct shout_data
*new_shout_data(void)
80 struct shout_data
*ret
= g_new(struct shout_data
, 1);
82 ret
->shout_conn
= shout_new();
83 ret
->shout_meta
= shout_metadata_new();
86 ret
->timeout
= DEFAULT_CONN_TIMEOUT
;
91 static void free_shout_data(struct shout_data
*sd
)
94 shout_metadata_free(sd
->shout_meta
);
96 shout_free(sd
->shout_conn
);
101 #define check_block_param(name) { \
102 block_param = config_get_block_param(param, name); \
103 if (!block_param) { \
104 g_error("no \"%s\" defined for shout device defined at line " \
105 "%i\n", name, param->line); \
110 my_shout_init_driver(const struct audio_format
*audio_format
,
111 const struct config_param
*param
,
114 struct shout_data
*sd
;
120 const char *encoding
;
121 const struct encoder_plugin
*encoder_plugin
;
122 unsigned shout_format
;
127 struct block_param
*block_param
;
130 if (audio_format
== NULL
||
131 !audio_format_fully_defined(audio_format
)) {
132 g_set_error(error
, shout_output_quark(), 0,
133 "Need full audio format specification");
137 sd
= new_shout_data();
139 if (shout_init_count
== 0)
144 check_block_param("host");
145 host
= block_param
->value
;
147 check_block_param("mount");
148 mount
= block_param
->value
;
150 port
= config_get_block_unsigned(param
, "port", 0);
152 g_set_error(error
, shout_output_quark(), 0,
153 "shout port must be configured");
157 check_block_param("password");
158 passwd
= block_param
->value
;
160 check_block_param("name");
161 name
= block_param
->value
;
163 public = config_get_block_bool(param
, "public", false);
165 user
= config_get_block_string(param
, "user", "source");
167 value
= config_get_block_string(param
, "quality", NULL
);
169 sd
->quality
= strtod(value
, &test
);
171 if (*test
!= '\0' || sd
->quality
< -1.0 || sd
->quality
> 10.0) {
172 g_set_error(error
, shout_output_quark(), 0,
173 "shout quality \"%s\" is not a number in the "
174 "range -1 to 10, line %i",
179 if (config_get_block_string(param
, "bitrate", NULL
) != NULL
) {
180 g_set_error(error
, shout_output_quark(), 0,
181 "quality and bitrate are "
186 value
= config_get_block_string(param
, "bitrate", NULL
);
188 g_set_error(error
, shout_output_quark(), 0,
189 "neither bitrate nor quality defined");
193 sd
->bitrate
= strtol(value
, &test
, 10);
195 if (*test
!= '\0' || sd
->bitrate
<= 0) {
196 g_set_error(error
, shout_output_quark(), 0,
197 "bitrate must be a positive integer");
202 encoding
= config_get_block_string(param
, "encoding", "ogg");
203 encoder_plugin
= shout_encoder_plugin_get(encoding
);
204 if (encoder_plugin
== NULL
) {
205 g_set_error(error
, shout_output_quark(), 0,
206 "couldn't find shout encoder plugin \"%s\"",
211 sd
->encoder
= encoder_init(encoder_plugin
, param
, error
);
212 if (sd
->encoder
== NULL
)
215 if (strcmp(encoding
, "mp3") == 0 || strcmp(encoding
, "lame") == 0)
216 shout_format
= SHOUT_FORMAT_MP3
;
218 shout_format
= SHOUT_FORMAT_OGG
;
220 value
= config_get_block_string(param
, "protocol", NULL
);
222 if (0 == strcmp(value
, "shoutcast") &&
223 0 != strcmp(encoding
, "mp3")) {
224 g_set_error(error
, shout_output_quark(), 0,
225 "you cannot stream \"%s\" to shoutcast, use mp3",
228 } else if (0 == strcmp(value
, "shoutcast"))
229 protocol
= SHOUT_PROTOCOL_ICY
;
230 else if (0 == strcmp(value
, "icecast1"))
231 protocol
= SHOUT_PROTOCOL_XAUDIOCAST
;
232 else if (0 == strcmp(value
, "icecast2"))
233 protocol
= SHOUT_PROTOCOL_HTTP
;
235 g_set_error(error
, shout_output_quark(), 0,
236 "shout protocol \"%s\" is not \"shoutcast\" or "
237 "\"icecast1\"or \"icecast2\"",
242 protocol
= SHOUT_PROTOCOL_HTTP
;
245 if (shout_set_host(sd
->shout_conn
, host
) != SHOUTERR_SUCCESS
||
246 shout_set_port(sd
->shout_conn
, port
) != SHOUTERR_SUCCESS
||
247 shout_set_password(sd
->shout_conn
, passwd
) != SHOUTERR_SUCCESS
||
248 shout_set_mount(sd
->shout_conn
, mount
) != SHOUTERR_SUCCESS
||
249 shout_set_name(sd
->shout_conn
, name
) != SHOUTERR_SUCCESS
||
250 shout_set_user(sd
->shout_conn
, user
) != SHOUTERR_SUCCESS
||
251 shout_set_public(sd
->shout_conn
, public) != SHOUTERR_SUCCESS
||
252 shout_set_format(sd
->shout_conn
, shout_format
)
253 != SHOUTERR_SUCCESS
||
254 shout_set_protocol(sd
->shout_conn
, protocol
) != SHOUTERR_SUCCESS
||
255 shout_set_agent(sd
->shout_conn
, "MPD") != SHOUTERR_SUCCESS
) {
256 g_set_error(error
, shout_output_quark(), 0,
257 "%s", shout_get_error(sd
->shout_conn
));
261 /* optional paramters */
262 sd
->timeout
= config_get_block_unsigned(param
, "timeout",
263 DEFAULT_CONN_TIMEOUT
);
265 value
= config_get_block_string(param
, "genre", NULL
);
266 if (value
!= NULL
&& shout_set_genre(sd
->shout_conn
, value
)) {
267 g_set_error(error
, shout_output_quark(), 0,
268 "%s", shout_get_error(sd
->shout_conn
));
272 value
= config_get_block_string(param
, "description", NULL
);
273 if (value
!= NULL
&& shout_set_description(sd
->shout_conn
, value
)) {
274 g_set_error(error
, shout_output_quark(), 0,
275 "%s", shout_get_error(sd
->shout_conn
));
281 memset(temp
, 0, sizeof(temp
));
283 snprintf(temp
, sizeof(temp
), "%u", audio_format
->channels
);
284 shout_set_audio_info(sd
->shout_conn
, SHOUT_AI_CHANNELS
, temp
);
286 snprintf(temp
, sizeof(temp
), "%u", audio_format
->sample_rate
);
288 shout_set_audio_info(sd
->shout_conn
, SHOUT_AI_SAMPLERATE
, temp
);
290 if (sd
->quality
>= -1.0) {
291 snprintf(temp
, sizeof(temp
), "%2.2f", sd
->quality
);
292 shout_set_audio_info(sd
->shout_conn
, SHOUT_AI_QUALITY
,
295 snprintf(temp
, sizeof(temp
), "%d", sd
->bitrate
);
296 shout_set_audio_info(sd
->shout_conn
, SHOUT_AI_BITRATE
,
305 handle_shout_error(struct shout_data
*sd
, int err
, GError
**error
)
308 case SHOUTERR_SUCCESS
:
311 case SHOUTERR_UNCONNECTED
:
312 case SHOUTERR_SOCKET
:
313 g_set_error(error
, shout_output_quark(), err
,
314 "Lost shout connection to %s:%i: %s",
315 shout_get_host(sd
->shout_conn
),
316 shout_get_port(sd
->shout_conn
),
317 shout_get_error(sd
->shout_conn
));
321 g_set_error(error
, shout_output_quark(), err
,
322 "connection to %s:%i error: %s",
323 shout_get_host(sd
->shout_conn
),
324 shout_get_port(sd
->shout_conn
),
325 shout_get_error(sd
->shout_conn
));
333 write_page(struct shout_data
*sd
, GError
**error
)
337 assert(sd
->encoder
!= NULL
);
339 sd
->buf
.len
= encoder_read(sd
->encoder
,
340 sd
->buf
.data
, sizeof(sd
->buf
.data
));
341 if (sd
->buf
.len
== 0)
344 shout_sync(sd
->shout_conn
);
345 err
= shout_send(sd
->shout_conn
, sd
->buf
.data
, sd
->buf
.len
);
346 if (!handle_shout_error(sd
, err
, error
))
352 static void close_shout_conn(struct shout_data
* sd
)
356 if (sd
->encoder
!= NULL
) {
357 if (encoder_flush(sd
->encoder
, NULL
))
358 write_page(sd
, NULL
);
360 encoder_close(sd
->encoder
);
363 if (shout_get_connected(sd
->shout_conn
) != SHOUTERR_UNCONNECTED
&&
364 shout_close(sd
->shout_conn
) != SHOUTERR_SUCCESS
) {
365 g_warning("problem closing connection to shout server: %s\n",
366 shout_get_error(sd
->shout_conn
));
370 static void my_shout_finish_driver(void *data
)
372 struct shout_data
*sd
= (struct shout_data
*)data
;
374 encoder_finish(sd
->encoder
);
380 if (shout_init_count
== 0)
384 static void my_shout_drop_buffered_audio(void *data
)
387 struct shout_data
*sd
= (struct shout_data
*)data
;
389 /* needs to be implemented for shout */
392 static void my_shout_close_device(void *data
)
394 struct shout_data
*sd
= (struct shout_data
*)data
;
396 close_shout_conn(sd
);
400 shout_connect(struct shout_data
*sd
, GError
**error
)
404 state
= shout_open(sd
->shout_conn
);
406 case SHOUTERR_SUCCESS
:
407 case SHOUTERR_CONNECTED
:
411 g_set_error(error
, shout_output_quark(), 0,
412 "problem opening connection to shout server %s:%i: %s",
413 shout_get_host(sd
->shout_conn
),
414 shout_get_port(sd
->shout_conn
),
415 shout_get_error(sd
->shout_conn
));
421 my_shout_open_device(void *data
, struct audio_format
*audio_format
,
424 struct shout_data
*sd
= (struct shout_data
*)data
;
427 ret
= shout_connect(sd
, error
);
433 ret
= encoder_open(sd
->encoder
, audio_format
, error
) &&
434 write_page(sd
, error
);
436 shout_close(sd
->shout_conn
);
444 my_shout_play(void *data
, const void *chunk
, size_t size
, GError
**error
)
446 struct shout_data
*sd
= (struct shout_data
*)data
;
448 return encoder_write(sd
->encoder
, chunk
, size
, error
) &&
449 write_page(sd
, error
)
455 my_shout_pause(void *data
)
457 struct shout_data
*sd
= (struct shout_data
*)data
;
458 static const char silence
[1020];
460 if (shout_delay(sd
->shout_conn
) > 500) {
461 /* cap the latency for unpause */
466 return my_shout_play(data
, silence
, sizeof(silence
), NULL
);
470 shout_tag_to_metadata(const struct tag
*tag
, char *dest
, size_t size
)
478 for (unsigned i
= 0; i
< tag
->num_items
; i
++) {
479 switch (tag
->items
[i
]->type
) {
481 strncpy(artist
, tag
->items
[i
]->value
, size
);
484 strncpy(title
, tag
->items
[i
]->value
, size
);
492 snprintf(dest
, size
, "%s - %s", title
, artist
);
495 static void my_shout_set_tag(void *data
,
496 const struct tag
*tag
)
498 struct shout_data
*sd
= (struct shout_data
*)data
;
500 GError
*error
= NULL
;
502 if (sd
->encoder
->plugin
->tag
!= NULL
) {
503 /* encoder plugin supports stream tags */
505 ret
= encoder_flush(sd
->encoder
, &error
);
507 g_warning("%s", error
->message
);
512 ret
= write_page(sd
, NULL
);
516 ret
= encoder_tag(sd
->encoder
, tag
, &error
);
518 g_warning("%s", error
->message
);
522 /* no stream tag support: fall back to icy-metadata */
525 shout_tag_to_metadata(tag
, song
, sizeof(song
));
527 shout_metadata_add(sd
->shout_meta
, "song", song
);
528 if (SHOUTERR_SUCCESS
!= shout_set_metadata(sd
->shout_conn
,
530 g_warning("error setting shout metadata\n");
534 write_page(sd
, NULL
);
537 const struct audio_output_plugin shoutPlugin
= {
539 .init
= my_shout_init_driver
,
540 .finish
= my_shout_finish_driver
,
541 .open
= my_shout_open_device
,
542 .play
= my_shout_play
,
543 .pause
= my_shout_pause
,
544 .cancel
= my_shout_drop_buffered_audio
,
545 .close
= my_shout_close_device
,
546 .send_tag
= my_shout_set_tag
,