Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
f6e5c007
Commit
f6e5c007
authored
Feb 22, 2009
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
shout: use the new encoder API
Removed shout's encoder plugin API in favor of the new generic encoder plugin API.
parent
f7c685f1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
103 additions
and
566 deletions
+103
-566
configure.ac
configure.ac
+1
-7
Makefile.am
src/Makefile.am
+0
-8
shout_mp3.c
src/output/shout_mp3.c
+0
-193
shout_ogg.c
src/output/shout_ogg.c
+0
-293
shout_plugin.c
src/output/shout_plugin.c
+101
-33
shout_plugin.h
src/output/shout_plugin.h
+1
-32
No files found.
configure.ac
View file @
f6e5c007
...
...
@@ -557,8 +557,7 @@ if test x$enable_shout_ogg = xyes; then
enable_shout_ogg=no
fi
if test x$enable_shout_ogg = xyes; then
PKG_CHECK_MODULES(VORBISENC, [vorbisenc],
AC_DEFINE(HAVE_SHOUT_OGG, 1, [Define to enable ogg streaming support]),
PKG_CHECK_MODULES(VORBISENC, [vorbisenc],,
enable_shout_ogg=no)
fi
fi
...
...
@@ -573,9 +572,6 @@ if test x$enable_shout_mp3 = xyes; then
AC_MSG_WARN([disabling mp3 shout streaming support because lame is not enabled])
enable_shout_mp3=no
fi
if test x$enable_shout_mp3 = xyes; then
AC_DEFINE(HAVE_SHOUT_MP3, 1, [Define to enable mp3 streaming support])
fi
fi
if test x$enable_shout_ogg = xyes || test x$enable_shout_mp3 = xyes; then
...
...
@@ -586,8 +582,6 @@ else
fi
AM_CONDITIONAL(HAVE_SHOUT, test x$enable_shout = xyes)
AM_CONDITIONAL(HAVE_SHOUT_OGG, test x$enable_shout_ogg = xyes)
AM_CONDITIONAL(HAVE_SHOUT_MP3, test x$enable_shout_mp3 = xyes)
AM_CONDITIONAL(ENABLE_ENCODER, test x$enable_shout = xyes)
AM_CONDITIONAL(ENABLE_VORBIS_ENCODER, test x$enable_shout_ogg = xyes)
...
...
src/Makefile.am
View file @
f6e5c007
...
...
@@ -419,14 +419,6 @@ if HAVE_SHOUT
mpd_SOURCES
+=
output/shout_plugin.c
endif
if
HAVE_SHOUT_MP3
mpd_SOURCES
+=
output/shout_mp3.c
endif
if
HAVE_SHOUT_OGG
mpd_SOURCES
+=
output/shout_ogg.c
endif
# sparse is a semantic parser
# URL: git://www.kernel.org/pub/scm/devel/sparse/sparse.git
SPARSE
=
sparse
...
...
src/output/shout_mp3.c
deleted
100644 → 0
View file @
f7c685f1
/* the Music Player Daemon (MPD)
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "shout_plugin.h"
#include <lame/lame.h>
#include <assert.h>
#include <stdlib.h>
struct
lame_data
{
lame_global_flags
*
gfp
;
};
static
int
shout_mp3_encoder_init
(
struct
shout_data
*
sd
)
{
struct
lame_data
*
ld
=
g_new
(
struct
lame_data
,
1
);
sd
->
encoder_data
=
ld
;
return
0
;
}
static
int
shout_mp3_encoder_clear_encoder
(
struct
shout_data
*
sd
)
{
struct
lame_data
*
ld
=
(
struct
lame_data
*
)
sd
->
encoder_data
;
struct
shout_buffer
*
buf
=
&
sd
->
buf
;
int
ret
;
ret
=
lame_encode_flush
(
ld
->
gfp
,
buf
->
data
,
sizeof
(
buf
->
data
));
if
(
ret
<
0
)
g_warning
(
"error flushing lame buffers
\n
"
);
lame_close
(
ld
->
gfp
);
ld
->
gfp
=
NULL
;
return
(
ret
>
0
);
}
static
void
shout_mp3_encoder_finish
(
struct
shout_data
*
sd
)
{
struct
lame_data
*
ld
=
(
struct
lame_data
*
)
sd
->
encoder_data
;
assert
(
ld
->
gfp
==
NULL
);
g_free
(
ld
);
}
static
int
shout_mp3_encoder_init_encoder
(
struct
shout_data
*
sd
)
{
struct
lame_data
*
ld
=
(
struct
lame_data
*
)
sd
->
encoder_data
;
if
(
NULL
==
(
ld
->
gfp
=
lame_init
()))
{
g_warning
(
"error initializing lame encoder for shout
\n
"
);
return
-
1
;
}
if
(
sd
->
quality
>=
-
1
.
0
)
{
if
(
0
!=
lame_set_VBR
(
ld
->
gfp
,
vbr_rh
))
{
g_warning
(
"error setting lame VBR mode
\n
"
);
return
-
1
;
}
if
(
0
!=
lame_set_VBR_q
(
ld
->
gfp
,
sd
->
quality
))
{
g_warning
(
"error setting lame VBR quality
\n
"
);
return
-
1
;
}
}
else
{
if
(
0
!=
lame_set_brate
(
ld
->
gfp
,
sd
->
bitrate
))
{
g_warning
(
"error setting lame bitrate
\n
"
);
return
-
1
;
}
}
if
(
0
!=
lame_set_num_channels
(
ld
->
gfp
,
sd
->
audio_format
.
channels
))
{
g_warning
(
"error setting lame num channels
\n
"
);
return
-
1
;
}
if
(
0
!=
lame_set_in_samplerate
(
ld
->
gfp
,
sd
->
audio_format
.
sample_rate
))
{
g_warning
(
"error setting lame sample rate
\n
"
);
return
-
1
;
}
if
(
0
>
lame_init_params
(
ld
->
gfp
))
g_error
(
"error initializing lame params
\n
"
);
return
0
;
}
static
int
shout_mp3_encoder_send_metadata
(
struct
shout_data
*
sd
,
char
*
song
,
size_t
size
)
{
char
artist
[
size
];
char
title
[
size
];
int
i
;
const
struct
tag
*
tag
=
sd
->
tag
;
strncpy
(
artist
,
""
,
size
);
strncpy
(
title
,
""
,
size
);
for
(
i
=
0
;
i
<
tag
->
numOfItems
;
i
++
)
{
switch
(
tag
->
items
[
i
]
->
type
)
{
case
TAG_ITEM_ARTIST
:
strncpy
(
artist
,
tag
->
items
[
i
]
->
value
,
size
);
break
;
case
TAG_ITEM_TITLE
:
strncpy
(
title
,
tag
->
items
[
i
]
->
value
,
size
);
break
;
default:
break
;
}
}
snprintf
(
song
,
size
,
"%s - %s"
,
title
,
artist
);
return
1
;
}
static
int
shout_mp3_encoder_encode
(
struct
shout_data
*
sd
,
const
void
*
chunk
,
size_t
len
)
{
const
int16_t
*
src
=
(
const
int16_t
*
)
chunk
;
unsigned
int
i
;
float
*
left
,
*
right
;
struct
shout_buffer
*
buf
=
&
(
sd
->
buf
);
unsigned
int
samples
;
struct
lame_data
*
ld
=
(
struct
lame_data
*
)
sd
->
encoder_data
;
int
bytes_out
;
samples
=
len
/
audio_format_sample_size
(
&
sd
->
audio_format
);
left
=
g_malloc
(
sizeof
(
left
[
0
])
*
samples
);
if
(
sd
->
audio_format
.
channels
>
1
)
right
=
g_malloc
(
sizeof
(
left
[
0
])
*
samples
);
else
right
=
left
;
/* this is for only 16-bit audio */
for
(
i
=
0
;
i
<
samples
;
i
++
)
{
left
[
i
]
=
src
[
0
];
if
(
right
!=
left
)
right
[
i
]
=
src
[
1
];
src
+=
sd
->
audio_format
.
channels
;
}
bytes_out
=
lame_encode_buffer_float
(
ld
->
gfp
,
left
,
right
,
samples
,
buf
->
data
,
sizeof
(
buf
->
data
));
g_free
(
left
);
if
(
right
!=
left
)
g_free
(
right
);
if
(
0
>
bytes_out
)
{
g_warning
(
"error encoding lame buffer for shout
\n
"
);
lame_close
(
ld
->
gfp
);
ld
->
gfp
=
NULL
;
return
-
1
;
}
else
buf
->
len
=
bytes_out
;
/* signed to unsigned conversion */
return
0
;
}
const
struct
shout_encoder_plugin
shout_mp3_encoder
=
{
"mp3"
,
SHOUT_FORMAT_MP3
,
shout_mp3_encoder_clear_encoder
,
shout_mp3_encoder_encode
,
shout_mp3_encoder_finish
,
shout_mp3_encoder_init
,
shout_mp3_encoder_init_encoder
,
shout_mp3_encoder_send_metadata
,
};
src/output/shout_ogg.c
deleted
100644 → 0
View file @
f7c685f1
/* the Music Player Daemon (MPD)
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "shout_plugin.h"
#include <vorbis/vorbisenc.h>
#include <stdlib.h>
struct
ogg_vorbis_data
{
ogg_stream_state
os
;
ogg_page
og
;
ogg_packet
op
;
ogg_packet
header_main
;
ogg_packet
header_comments
;
ogg_packet
header_codebooks
;
vorbis_dsp_state
vd
;
vorbis_block
vb
;
vorbis_info
vi
;
vorbis_comment
vc
;
};
static
void
add_tag
(
struct
ogg_vorbis_data
*
od
,
const
char
*
name
,
char
*
value
)
{
if
(
value
)
{
union
{
const
char
*
in
;
char
*
out
;
}
u
=
{
.
in
=
name
};
vorbis_comment_add_tag
(
&
od
->
vc
,
u
.
out
,
value
);
}
}
static
void
copy_tag_to_vorbis_comment
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
if
(
sd
->
tag
)
{
int
i
;
for
(
i
=
0
;
i
<
sd
->
tag
->
numOfItems
;
i
++
)
{
switch
(
sd
->
tag
->
items
[
i
]
->
type
)
{
case
TAG_ITEM_ARTIST
:
add_tag
(
od
,
"ARTIST"
,
sd
->
tag
->
items
[
i
]
->
value
);
break
;
case
TAG_ITEM_ALBUM
:
add_tag
(
od
,
"ALBUM"
,
sd
->
tag
->
items
[
i
]
->
value
);
break
;
case
TAG_ITEM_TITLE
:
add_tag
(
od
,
"TITLE"
,
sd
->
tag
->
items
[
i
]
->
value
);
break
;
default:
break
;
}
}
}
}
static
int
copy_ogg_buffer_to_shout_buffer
(
ogg_page
*
og
,
struct
shout_buffer
*
buf
)
{
if
((
size_t
)
og
->
header_len
+
(
size_t
)
og
->
body_len
>
sizeof
(
buf
->
data
))
{
g_warning
(
"%s: not enough buffer space!
\n
"
,
__func__
);
return
-
1
;
}
memcpy
(
buf
->
data
,
og
->
header
,
og
->
header_len
);
memcpy
(
buf
->
data
+
og
->
header_len
,
og
->
body
,
og
->
body_len
);
buf
->
len
=
og
->
header_len
+
og
->
body_len
;
return
0
;
}
static
int
flush_ogg_buffer
(
struct
shout_data
*
sd
)
{
struct
shout_buffer
*
buf
=
&
sd
->
buf
;
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
int
ret
=
0
;
if
(
ogg_stream_flush
(
&
od
->
os
,
&
od
->
og
))
ret
=
copy_ogg_buffer_to_shout_buffer
(
&
od
->
og
,
buf
);
return
ret
;
}
static
int
send_ogg_vorbis_header
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
vorbis_analysis_headerout
(
&
od
->
vd
,
&
od
->
vc
,
&
od
->
header_main
,
&
od
->
header_comments
,
&
od
->
header_codebooks
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_main
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_comments
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_codebooks
);
return
flush_ogg_buffer
(
sd
);
}
static
void
finish_encoder
(
struct
ogg_vorbis_data
*
od
)
{
vorbis_analysis_wrote
(
&
od
->
vd
,
0
);
while
(
vorbis_analysis_blockout
(
&
od
->
vd
,
&
od
->
vb
)
==
1
)
{
vorbis_analysis
(
&
od
->
vb
,
NULL
);
vorbis_bitrate_addblock
(
&
od
->
vb
);
while
(
vorbis_bitrate_flushpacket
(
&
od
->
vd
,
&
od
->
op
))
{
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
op
);
}
}
}
static
int
shout_ogg_encoder_clear_encoder
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
int
ret
;
finish_encoder
(
od
);
if
((
ret
=
ogg_stream_pageout
(
&
od
->
os
,
&
od
->
og
)))
copy_ogg_buffer_to_shout_buffer
(
&
od
->
og
,
&
sd
->
buf
);
vorbis_comment_clear
(
&
od
->
vc
);
ogg_stream_clear
(
&
od
->
os
);
vorbis_block_clear
(
&
od
->
vb
);
vorbis_dsp_clear
(
&
od
->
vd
);
vorbis_info_clear
(
&
od
->
vi
);
return
ret
;
}
static
void
shout_ogg_encoder_finish
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
if
(
od
)
{
free
(
od
);
sd
->
encoder_data
=
NULL
;
}
}
static
int
shout_ogg_encoder_init
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
g_new
(
struct
ogg_vorbis_data
,
1
);
sd
->
encoder_data
=
od
;
return
0
;
}
static
int
reinit_encoder
(
struct
shout_data
*
sd
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
vorbis_info_init
(
&
od
->
vi
);
if
(
sd
->
quality
>=
-
1
.
0
)
{
if
(
0
!=
vorbis_encode_init_vbr
(
&
od
->
vi
,
sd
->
audio_format
.
channels
,
sd
->
audio_format
.
sample_rate
,
sd
->
quality
*
0
.
1
))
{
g_warning
(
"error initializing vorbis vbr
\n
"
);
vorbis_info_clear
(
&
od
->
vi
);
return
-
1
;
}
}
else
{
if
(
0
!=
vorbis_encode_init
(
&
od
->
vi
,
sd
->
audio_format
.
channels
,
sd
->
audio_format
.
sample_rate
,
-
1
.
0
,
sd
->
bitrate
*
1000
,
-
1
.
0
))
{
g_warning
(
"error initializing vorbis encoder
\n
"
);
vorbis_info_clear
(
&
od
->
vi
);
return
-
1
;
}
}
vorbis_analysis_init
(
&
od
->
vd
,
&
od
->
vi
);
vorbis_block_init
(
&
od
->
vd
,
&
od
->
vb
);
ogg_stream_init
(
&
od
->
os
,
rand
());
vorbis_comment_init
(
&
od
->
vc
);
return
0
;
}
static
int
shout_ogg_encoder_init_encoder
(
struct
shout_data
*
sd
)
{
if
(
reinit_encoder
(
sd
))
return
-
1
;
if
(
send_ogg_vorbis_header
(
sd
))
{
g_warning
(
"error sending ogg vorbis header for shout
\n
"
);
return
-
1
;
}
return
0
;
}
static
int
shout_ogg_encoder_send_metadata
(
struct
shout_data
*
sd
,
G_GNUC_UNUSED
char
*
song
,
G_GNUC_UNUSED
size_t
size
)
{
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
shout_ogg_encoder_clear_encoder
(
sd
);
if
(
reinit_encoder
(
sd
))
return
0
;
copy_tag_to_vorbis_comment
(
sd
);
vorbis_analysis_headerout
(
&
od
->
vd
,
&
od
->
vc
,
&
od
->
header_main
,
&
od
->
header_comments
,
&
od
->
header_codebooks
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_main
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_comments
);
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
header_codebooks
);
flush_ogg_buffer
(
sd
);
return
0
;
}
static
void
pcm16_to_ogg_buffer
(
float
**
dest
,
const
int16_t
*
src
,
unsigned
num_samples
,
unsigned
num_channels
)
{
for
(
unsigned
i
=
0
;
i
<
num_samples
;
i
++
)
for
(
unsigned
j
=
0
;
j
<
num_channels
;
j
++
)
dest
[
j
][
i
]
=
*
src
++
/
32768
.
0
;
}
static
int
shout_ogg_encoder_encode
(
struct
shout_data
*
sd
,
const
void
*
chunk
,
size_t
size
)
{
struct
shout_buffer
*
buf
=
&
sd
->
buf
;
unsigned
int
samples
;
struct
ogg_vorbis_data
*
od
=
(
struct
ogg_vorbis_data
*
)
sd
->
encoder_data
;
samples
=
size
/
audio_format_frame_size
(
&
sd
->
audio_format
);
/* this is for only 16-bit audio */
pcm16_to_ogg_buffer
(
vorbis_analysis_buffer
(
&
od
->
vd
,
samples
),
(
const
int16_t
*
)
chunk
,
samples
,
sd
->
audio_format
.
channels
);
vorbis_analysis_wrote
(
&
od
->
vd
,
samples
);
while
(
1
==
vorbis_analysis_blockout
(
&
od
->
vd
,
&
od
->
vb
))
{
vorbis_analysis
(
&
od
->
vb
,
NULL
);
vorbis_bitrate_addblock
(
&
od
->
vb
);
while
(
vorbis_bitrate_flushpacket
(
&
od
->
vd
,
&
od
->
op
))
{
ogg_stream_packetin
(
&
od
->
os
,
&
od
->
op
);
}
}
if
(
ogg_stream_pageout
(
&
od
->
os
,
&
od
->
og
))
copy_ogg_buffer_to_shout_buffer
(
&
od
->
og
,
buf
);
return
0
;
}
const
struct
shout_encoder_plugin
shout_ogg_encoder
=
{
"ogg"
,
SHOUT_FORMAT_VORBIS
,
shout_ogg_encoder_clear_encoder
,
shout_ogg_encoder_encode
,
shout_ogg_encoder_finish
,
shout_ogg_encoder_init
,
shout_ogg_encoder_init_encoder
,
shout_ogg_encoder_send_metadata
,
};
src/output/shout_plugin.c
View file @
f6e5c007
...
...
@@ -17,6 +17,8 @@
*/
#include "shout_plugin.h"
#include "encoder_plugin.h"
#include "encoder_list.h"
#include "config.h"
#include <assert.h>
...
...
@@ -37,16 +39,15 @@ static const struct shout_encoder_plugin *const shout_encoder_plugins[] = {
NULL
};
static
const
struct
shout_
encoder_plugin
*
static
const
struct
encoder_plugin
*
shout_encoder_plugin_get
(
const
char
*
name
)
{
unsigned
i
;
if
(
strcmp
(
name
,
"ogg"
)
==
0
)
name
=
"vorbis"
;
else
if
(
strcmp
(
name
,
"mp3"
)
==
0
)
name
=
"lame"
;
for
(
i
=
0
;
shout_encoder_plugins
[
i
]
!=
NULL
;
++
i
)
if
(
strcmp
(
shout_encoder_plugins
[
i
]
->
name
,
name
)
==
0
)
return
shout_encoder_plugins
[
i
];
return
NULL
;
return
encoder_plugin_get
(
name
);
}
static
struct
shout_data
*
new_shout_data
(
void
)
...
...
@@ -91,6 +92,9 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
char
*
mount
;
char
*
passwd
;
const
char
*
encoding
;
const
struct
encoder_plugin
*
encoder_plugin
;
GError
*
error
=
NULL
;
unsigned
shout_format
;
unsigned
protocol
;
const
char
*
user
;
char
*
name
;
...
...
@@ -162,15 +166,21 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
check_block_param
(
"format"
);
assert
(
audio_format
!=
NULL
);
sd
->
audio_format
=
*
audio_format
;
encoding
=
config_get_block_string
(
param
,
"encoding"
,
"ogg"
);
sd
->
encoder
=
shout_encoder_plugin_get
(
encoding
);
if
(
sd
->
encoder
==
NULL
)
encoder_plugin
=
shout_encoder_plugin_get
(
encoding
);
if
(
encoder_plugin
==
NULL
)
g_error
(
"couldn't find shout encoder plugin
\"
%s
\"\n
"
,
encoding
);
sd
->
encoder
=
encoder_init
(
encoder_plugin
,
param
,
&
error
);
if
(
sd
->
encoder
==
NULL
)
g_error
(
"%s"
,
error
->
message
);
if
(
strcmp
(
encoding
,
"mp3"
)
==
0
||
strcmp
(
encoding
,
"lame"
)
==
0
)
shout_format
=
SHOUT_FORMAT_MP3
;
else
shout_format
=
SHOUT_FORMAT_OGG
;
value
=
config_get_block_string
(
param
,
"protocol"
,
NULL
);
if
(
value
!=
NULL
)
{
if
(
0
==
strcmp
(
value
,
"shoutcast"
)
&&
...
...
@@ -199,7 +209,7 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
shout_set_name
(
sd
->
shout_conn
,
name
)
!=
SHOUTERR_SUCCESS
||
shout_set_user
(
sd
->
shout_conn
,
user
)
!=
SHOUTERR_SUCCESS
||
shout_set_public
(
sd
->
shout_conn
,
public
)
!=
SHOUTERR_SUCCESS
||
shout_set_format
(
sd
->
shout_conn
,
s
d
->
encoder
->
s
hout_format
)
shout_set_format
(
sd
->
shout_conn
,
shout_format
)
!=
SHOUTERR_SUCCESS
||
shout_set_protocol
(
sd
->
shout_conn
,
protocol
)
!=
SHOUTERR_SUCCESS
||
shout_set_agent
(
sd
->
shout_conn
,
"MPD"
)
!=
SHOUTERR_SUCCESS
)
{
...
...
@@ -227,10 +237,10 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
char
temp
[
11
];
memset
(
temp
,
0
,
sizeof
(
temp
));
snprintf
(
temp
,
sizeof
(
temp
),
"%u"
,
sd
->
audio_format
.
channels
);
snprintf
(
temp
,
sizeof
(
temp
),
"%u"
,
audio_format
->
channels
);
shout_set_audio_info
(
sd
->
shout_conn
,
SHOUT_AI_CHANNELS
,
temp
);
snprintf
(
temp
,
sizeof
(
temp
),
"%u"
,
sd
->
audio_format
.
sample_rate
);
snprintf
(
temp
,
sizeof
(
temp
),
"%u"
,
audio_format
->
sample_rate
);
shout_set_audio_info
(
sd
->
shout_conn
,
SHOUT_AI_SAMPLERATE
,
temp
);
...
...
@@ -245,10 +255,6 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
}
}
if
(
sd
->
encoder
->
init_func
(
sd
)
!=
0
)
g_error
(
"shout: encoder plugin '%s' failed to initialize
\n
"
,
sd
->
encoder
->
name
);
return
sd
;
}
...
...
@@ -283,6 +289,10 @@ write_page(struct shout_data *sd)
{
int
err
;
assert
(
sd
->
encoder
!=
NULL
);
sd
->
buf
.
len
=
encoder_read
(
sd
->
encoder
,
sd
->
buf
.
data
,
sizeof
(
sd
->
buf
.
data
));
if
(
sd
->
buf
.
len
==
0
)
return
true
;
...
...
@@ -298,8 +308,12 @@ static void close_shout_conn(struct shout_data * sd)
{
sd
->
buf
.
len
=
0
;
if
(
sd
->
encoder
->
clear_encoder_func
(
sd
))
write_page
(
sd
);
if
(
sd
->
encoder
!=
NULL
)
{
if
(
encoder_flush
(
sd
->
encoder
,
NULL
))
write_page
(
sd
);
encoder_close
(
sd
->
encoder
);
}
if
(
shout_get_connected
(
sd
->
shout_conn
)
!=
SHOUTERR_UNCONNECTED
&&
shout_close
(
sd
->
shout_conn
)
!=
SHOUTERR_SUCCESS
)
{
...
...
@@ -312,7 +326,8 @@ static void my_shout_finish_driver(void *data)
{
struct
shout_data
*
sd
=
(
struct
shout_data
*
)
data
;
sd
->
encoder
->
finish_func
(
sd
);
encoder_finish
(
sd
->
encoder
);
free_shout_data
(
sd
);
shout_init_count
--
;
...
...
@@ -357,11 +372,11 @@ shout_connect(struct shout_data *sd)
}
static
bool
my_shout_open_device
(
void
*
data
,
G_GNUC_UNUSED
struct
audio_format
*
audio_format
)
my_shout_open_device
(
void
*
data
,
struct
audio_format
*
audio_format
)
{
struct
shout_data
*
sd
=
(
struct
shout_data
*
)
data
;
bool
ret
;
GError
*
error
=
NULL
;
ret
=
shout_connect
(
sd
);
if
(
!
ret
)
...
...
@@ -369,8 +384,11 @@ my_shout_open_device(void *data,
sd
->
buf
.
len
=
0
;
if
(
sd
->
encoder
->
init_encoder_func
(
sd
)
<
0
)
{
ret
=
encoder_open
(
sd
->
encoder
,
audio_format
,
&
error
);
if
(
!
ret
)
{
shout_close
(
sd
->
shout_conn
);
g_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
return
false
;
}
...
...
@@ -383,11 +401,15 @@ static bool
my_shout_play
(
void
*
data
,
const
char
*
chunk
,
size_t
size
)
{
struct
shout_data
*
sd
=
(
struct
shout_data
*
)
data
;
bool
ret
;
GError
*
error
=
NULL
;
sd
->
buf
.
len
=
0
;
if
(
sd
->
encoder
->
encode_func
(
sd
,
chunk
,
size
))
ret
=
encoder_write
(
sd
->
encoder
,
chunk
,
size
,
&
error
);
if
(
!
ret
)
{
g_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
return
false
;
}
return
write_page
(
sd
);
}
...
...
@@ -400,17 +422,63 @@ my_shout_pause(void *data)
return
my_shout_play
(
data
,
silence
,
sizeof
(
silence
));
}
static
void
shout_tag_to_metadata
(
const
struct
tag
*
tag
,
char
*
dest
,
size_t
size
)
{
char
artist
[
size
];
char
title
[
size
];
int
i
;
artist
[
0
]
=
0
;
title
[
0
]
=
0
;
for
(
i
=
0
;
i
<
tag
->
numOfItems
;
i
++
)
{
switch
(
tag
->
items
[
i
]
->
type
)
{
case
TAG_ITEM_ARTIST
:
strncpy
(
artist
,
tag
->
items
[
i
]
->
value
,
size
);
break
;
case
TAG_ITEM_TITLE
:
strncpy
(
title
,
tag
->
items
[
i
]
->
value
,
size
);
break
;
default:
break
;
}
}
snprintf
(
dest
,
size
,
"%s - %s"
,
title
,
artist
);
}
static
void
my_shout_set_tag
(
void
*
data
,
const
struct
tag
*
tag
)
{
struct
shout_data
*
sd
=
(
struct
shout_data
*
)
data
;
char
song
[
1024
];
bool
ret
;
GError
*
error
=
NULL
;
if
(
sd
->
encoder
->
plugin
->
tag
!=
NULL
)
{
/* encoder plugin supports stream tags */
ret
=
encoder_flush
(
sd
->
encoder
,
&
error
);
if
(
!
ret
)
{
g_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
return
;
}
write_page
(
sd
);
ret
=
encoder_tag
(
sd
->
encoder
,
tag
,
&
error
);
if
(
!
ret
)
{
g_warning
(
"%s"
,
error
->
message
);
g_error_free
(
error
);
}
}
else
{
/* no stream tag support: fall back to icy-metadata */
char
song
[
1024
];
shout_tag_to_metadata
(
tag
,
song
,
sizeof
(
song
));
sd
->
buf
.
len
=
0
;
sd
->
tag
=
tag
;
ret
=
sd
->
encoder
->
send_metadata_func
(
sd
,
song
,
sizeof
(
song
));
if
(
ret
)
{
shout_metadata_add
(
sd
->
shout_meta
,
"song"
,
song
);
if
(
SHOUTERR_SUCCESS
!=
shout_set_metadata
(
sd
->
shout_conn
,
sd
->
shout_meta
))
{
...
...
src/output/shout_plugin.h
View file @
f6e5c007
...
...
@@ -28,28 +28,6 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "shout"
struct
shout_data
;
struct
shout_encoder_plugin
{
const
char
*
name
;
unsigned
int
shout_format
;
int
(
*
clear_encoder_func
)(
struct
shout_data
*
sd
);
int
(
*
encode_func
)(
struct
shout_data
*
sd
,
const
void
*
chunk
,
size_t
len
);
void
(
*
finish_func
)(
struct
shout_data
*
sd
);
int
(
*
init_func
)(
struct
shout_data
*
sd
);
int
(
*
init_encoder_func
)
(
struct
shout_data
*
sd
);
/* Called when there is a new MpdTag to encode into the
stream. If this function returns non-zero, then the
resulting song will be passed to the shout server as
metadata. This allows the Ogg encoder to send metadata via
Vorbis comments in the stream, while an MP3 encoder can use
the Shout Server's metadata API. */
int
(
*
send_metadata_func
)(
struct
shout_data
*
sd
,
char
*
song
,
size_t
size
);
};
struct
shout_buffer
{
unsigned
char
data
[
32768
];
size_t
len
;
...
...
@@ -61,23 +39,14 @@ struct shout_data {
shout_t
*
shout_conn
;
shout_metadata_t
*
shout_meta
;
const
struct
shout_encoder_plugin
*
encoder
;
void
*
encoder_data
;
struct
encoder
*
encoder
;
float
quality
;
int
bitrate
;
const
struct
tag
*
tag
;
int
timeout
;
/* the configured audio format */
struct
audio_format
audio_format
;
struct
shout_buffer
buf
;
};
extern
const
struct
shout_encoder_plugin
shout_mp3_encoder
;
extern
const
struct
shout_encoder_plugin
shout_ogg_encoder
;
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment