mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-15 08:29:45 +00:00
stick a fork in it.... needs testing and tweaks but can now read and write to icecast via shout:// and or .mp3 files the traditional way
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4597 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
504798a64a
commit
84e012c0d9
@ -13,7 +13,7 @@ void InitMP3Constants(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOL InitMP3(struct mpstr *mp, long outscale)
|
BOOL InitMP3(struct mpstr *mp, long outscale, int samplerate)
|
||||||
{
|
{
|
||||||
/* quiet 4096 med 8192 */
|
/* quiet 4096 med 8192 */
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ BOOL InitMP3(struct mpstr *mp, long outscale)
|
|||||||
mp->fr.single = 3; /* force mono */
|
mp->fr.single = 3; /* force mono */
|
||||||
mp->bsnum = 0;
|
mp->bsnum = 0;
|
||||||
mp->synth_bo = 1;
|
mp->synth_bo = 1;
|
||||||
mp->outsamplerate = 8000;
|
mp->outsamplerate = samplerate;
|
||||||
|
|
||||||
make_decode_tables_scale(mp, outscale);
|
make_decode_tables_scale(mp, outscale);
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ int decodeMP3(struct mpstr *mp,char *in,int isize,char *out,
|
|||||||
|
|
||||||
if(osize < 4608) {
|
if(osize < 4608) {
|
||||||
debug_printf("%d To less out space\n", __LINE__);
|
debug_printf("%d To less out space\n", __LINE__);
|
||||||
return MP3_ERR;
|
return MP3_TOOSMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(in) {
|
if(in) {
|
||||||
|
@ -38,13 +38,14 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
|
||||||
#define OUTSCALE 4096
|
#define OUTSCALE 8192
|
||||||
#define MP3_SCACHE 16384
|
#define MP3_SCACHE 16384
|
||||||
#define MP3_DCACHE 8192
|
#define MP3_DCACHE 8192
|
||||||
|
|
||||||
static const char modname[] = "mod_shout";
|
static const char modname[] = "mod_shout";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char *supported_formats[SWITCH_MAX_CODECS] = {0};
|
static char *supported_formats[SWITCH_MAX_CODECS] = {0};
|
||||||
|
|
||||||
struct shout_context {
|
struct shout_context {
|
||||||
@ -52,32 +53,52 @@ struct shout_context {
|
|||||||
lame_global_flags *gfp;
|
lame_global_flags *gfp;
|
||||||
char *stream_url;
|
char *stream_url;
|
||||||
switch_mutex_t *audio_mutex;
|
switch_mutex_t *audio_mutex;
|
||||||
switch_mutex_t *mp3_mutex;
|
|
||||||
switch_buffer_t *audio_buffer;
|
switch_buffer_t *audio_buffer;
|
||||||
switch_buffer_t *mp3_buffer;
|
|
||||||
switch_memory_pool_t *memory_pool;
|
switch_memory_pool_t *memory_pool;
|
||||||
//char encode_buf[MP3_SCACHE];
|
|
||||||
char decode_buf[MP3_DCACHE];
|
char decode_buf[MP3_DCACHE];
|
||||||
struct mpstr mp;
|
struct mpstr mp;
|
||||||
int err;
|
int err;
|
||||||
|
int mp3err;
|
||||||
int dlen;
|
int dlen;
|
||||||
|
switch_file_t *fd;
|
||||||
|
FILE *fp;
|
||||||
|
int samplerate;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct shout_context shout_context_t;
|
typedef struct shout_context shout_context_t;
|
||||||
|
|
||||||
|
|
||||||
|
static size_t decode_fd(shout_context_t *context, void *data, size_t bytes);
|
||||||
|
|
||||||
static inline void free_context(shout_context_t *context)
|
static inline void free_context(shout_context_t *context)
|
||||||
{
|
{
|
||||||
if (context) {
|
if (context) {
|
||||||
|
int sanity = 0;
|
||||||
|
|
||||||
|
if (context->fd) {
|
||||||
|
switch_file_close(context->fd);
|
||||||
|
context->fd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->fp) {
|
||||||
|
unsigned char mp3buffer[1024];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
while ((len = lame_encode_flush(context->gfp, mp3buffer, sizeof(mp3buffer))) > 0) {
|
||||||
|
fwrite(mp3buffer, 1, len, context->fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
lame_mp3_tags_fid(context->gfp, context->fp);
|
||||||
|
fclose(context->fp);
|
||||||
|
context->fp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (context->audio_buffer) {
|
if (context->audio_buffer) {
|
||||||
switch_mutex_lock(context->audio_mutex);
|
switch_mutex_lock(context->audio_mutex);
|
||||||
switch_buffer_destroy(&context->audio_buffer);
|
switch_buffer_destroy(&context->audio_buffer);
|
||||||
switch_mutex_unlock(context->audio_mutex);
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->mp3_buffer) {
|
|
||||||
switch_buffer_destroy(&context->mp3_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->shout) {
|
if (context->shout) {
|
||||||
shout_close(context->shout);
|
shout_close(context->shout);
|
||||||
context->shout = NULL;
|
context->shout = NULL;
|
||||||
@ -87,6 +108,22 @@ static inline void free_context(shout_context_t *context)
|
|||||||
lame_close(context->gfp);
|
lame_close(context->gfp);
|
||||||
context->gfp = NULL;
|
context->gfp = NULL;
|
||||||
}
|
}
|
||||||
|
if (context->stream_url) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
err = ++context->err;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
|
|
||||||
|
while(context->err == err) {
|
||||||
|
switch_yield(1000000);
|
||||||
|
if (++sanity > 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitMP3(&context->mp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,21 +206,119 @@ static void log_msg(char const *fmt, va_list ap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t decode_fd(shout_context_t *context, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
int decode_status = 0;
|
||||||
|
int dlen = 0;
|
||||||
|
int x = 0;
|
||||||
|
char *in;
|
||||||
|
int inlen;
|
||||||
|
char *out;
|
||||||
|
int outlen;
|
||||||
|
int usedlen;
|
||||||
|
char inbuf[MP3_SCACHE];
|
||||||
|
int done = 0;
|
||||||
|
|
||||||
|
size_t lp;
|
||||||
|
size_t rb = 0;
|
||||||
|
|
||||||
|
while (switch_buffer_inuse(context->audio_buffer) < bytes) {
|
||||||
|
lp = sizeof(inbuf);
|
||||||
|
if ((switch_file_read(context->fd, inbuf, &lp) != SWITCH_STATUS_SUCCESS) || lp == 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
inlen = (int) lp;
|
||||||
|
in = inbuf;
|
||||||
|
|
||||||
|
out = context->decode_buf;
|
||||||
|
outlen = (int) sizeof(context->decode_buf);
|
||||||
|
usedlen = 0;
|
||||||
|
x = 0;
|
||||||
|
if (inlen < bytes) {
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
decode_status = decodeMP3(&context->mp, in, inlen, out, outlen, &dlen);
|
||||||
|
|
||||||
|
if (context->err) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x) {
|
||||||
|
in = NULL;
|
||||||
|
inlen = 0;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode_status == MP3_TOOSMALL) {
|
||||||
|
if (context->audio_buffer) {
|
||||||
|
switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = context->decode_buf;
|
||||||
|
outlen = sizeof(context->decode_buf);
|
||||||
|
usedlen = 0;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode_status == MP3_ERR) {
|
||||||
|
if (++context->mp3err >= 20) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error!\n");
|
||||||
|
}
|
||||||
|
dlen = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->mp3err = 0;
|
||||||
|
|
||||||
|
usedlen += dlen;
|
||||||
|
out += dlen;
|
||||||
|
outlen -= dlen;
|
||||||
|
dlen = 0;
|
||||||
|
|
||||||
|
|
||||||
|
} while (decode_status != MP3_NEED_MORE);
|
||||||
|
|
||||||
|
|
||||||
|
if (context->audio_buffer) {
|
||||||
|
switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_buffer_inuse(context->audio_buffer) >= bytes) {
|
||||||
|
rb = switch_buffer_read(context->audio_buffer, data, bytes);
|
||||||
|
return rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
context->err++;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static int wtf = -1;
|
|
||||||
|
|
||||||
static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||||
{
|
{
|
||||||
register unsigned int realsize = (unsigned int)(size * nmemb);
|
register unsigned int realsize = (unsigned int)(size * nmemb);
|
||||||
shout_context_t *context = data;
|
shout_context_t *context = data;
|
||||||
int rlen;
|
|
||||||
char grr[1024];
|
|
||||||
char *ass;
|
|
||||||
int decode_status = 0;
|
int decode_status = 0;
|
||||||
int dlen = 0;
|
int dlen = 0;
|
||||||
int offset = 0;
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
|
||||||
char *in;
|
char *in;
|
||||||
int inlen;
|
int inlen;
|
||||||
char *out;
|
char *out;
|
||||||
@ -200,37 +335,65 @@ static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
|||||||
do {
|
do {
|
||||||
decode_status = decodeMP3(&context->mp, in, inlen, out, outlen, &dlen);
|
decode_status = decodeMP3(&context->mp, in, inlen, out, outlen, &dlen);
|
||||||
|
|
||||||
|
if (context->err) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!x) {
|
if (!x) {
|
||||||
in = NULL;
|
in = NULL;
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decode_status == MP3_ERR) {
|
if (decode_status == MP3_TOOSMALL) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error!\n");
|
switch_mutex_lock(context->audio_mutex);
|
||||||
context->err++;
|
if (context->audio_buffer) {
|
||||||
return 0;
|
switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
out = context->decode_buf;
|
||||||
|
outlen = sizeof(context->decode_buf);
|
||||||
|
usedlen = 0;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
|
|
||||||
|
} else if (decode_status == MP3_ERR) {
|
||||||
|
|
||||||
|
if (++context->mp3err >= 20) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error!\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitMP3(&context->mp);
|
||||||
|
InitMP3(&context->mp, OUTSCALE, context->samplerate);
|
||||||
|
|
||||||
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context->mp3err = 0;
|
||||||
usedlen += dlen;
|
usedlen += dlen;
|
||||||
out += dlen;
|
out += dlen;
|
||||||
outlen -= dlen;
|
outlen -= dlen;
|
||||||
dlen = 0;
|
dlen = 0;
|
||||||
} while (decode_status != MP3_NEED_MORE);
|
} while (decode_status != MP3_NEED_MORE);
|
||||||
|
|
||||||
printf("WRITE %d\n", usedlen);
|
|
||||||
switch_mutex_lock(context->audio_mutex);
|
switch_mutex_lock(context->audio_mutex);
|
||||||
switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
|
if (context->audio_buffer) {
|
||||||
|
switch_buffer_write(context->audio_buffer, context->decode_buf, usedlen);
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
switch_mutex_unlock(context->audio_mutex);
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
out = context->decode_buf;
|
|
||||||
outlen = sizeof(context->decode_buf);
|
|
||||||
|
|
||||||
printf("doh\n");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return realsize;
|
return realsize;
|
||||||
|
|
||||||
|
error:
|
||||||
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
context->err++;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -248,7 +411,10 @@ static void *SWITCH_THREAD_FUNC stream_thread(switch_thread_t *thread, void *obj
|
|||||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "FreeSWITCH(mod_shout)/1.0");
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "FreeSWITCH(mod_shout)/1.0");
|
||||||
curl_easy_perform(curl_handle);
|
curl_easy_perform(curl_handle);
|
||||||
curl_easy_cleanup(curl_handle);
|
curl_easy_cleanup(curl_handle);
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Thread Done\n");
|
||||||
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
context->err++;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,115 +440,130 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, char *path)
|
|||||||
return SWITCH_STATUS_MEMERR;
|
return SWITCH_STATUS_MEMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(context->shout = shout_new())) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate shout_t\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(context->gfp = lame_init())) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->memory_pool = handle->memory_pool;
|
context->memory_pool = handle->memory_pool;
|
||||||
|
context->samplerate = handle->codec_imp ? handle->codec_imp->samples_per_second : 8000;
|
||||||
lame_set_num_channels(context->gfp, handle->channels);
|
|
||||||
lame_set_in_samplerate(context->gfp, handle->samplerate);
|
|
||||||
lame_set_brate(context->gfp, 24);
|
|
||||||
lame_set_mode(context->gfp, 3);
|
|
||||||
lame_set_quality(context->gfp, 2); /* 2=high 5 = medium 7=low */
|
|
||||||
|
|
||||||
lame_set_errorf(context->gfp, log_error);
|
|
||||||
lame_set_debugf(context->gfp, log_debug);
|
|
||||||
lame_set_msgf(context->gfp, log_msg);
|
|
||||||
lame_set_bWriteVbrTag(context->gfp, 0);
|
|
||||||
lame_mp3_tags_fid(context->gfp, NULL);
|
|
||||||
lame_init_params(context->gfp);
|
|
||||||
lame_print_config(context->gfp);
|
|
||||||
|
|
||||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
|
if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
|
||||||
if (switch_buffer_create_dynamic(&context->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
|
if (switch_buffer_create_dynamic(&context->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (switch_buffer_create_dynamic(&context->mp3_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->memory_pool);
|
|
||||||
switch_mutex_init(&context->mp3_mutex, SWITCH_MUTEX_NESTED, context->memory_pool);
|
|
||||||
InitMP3(&context->mp, OUTSCALE);
|
|
||||||
context->stream_url = switch_core_sprintf(context->memory_pool, "http://%s", path);
|
|
||||||
launch_stream_thread(context);
|
|
||||||
} else if (!switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
|
||||||
username = switch_core_strdup(handle->memory_pool, path);
|
|
||||||
if (!(password = strchr(username, ':'))) {
|
|
||||||
err = "invalid url";
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
*password++ = '\0';
|
|
||||||
|
|
||||||
if (!(host = strchr(password, '@'))) {
|
switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->memory_pool);
|
||||||
err = "invalid url";
|
InitMP3(&context->mp, OUTSCALE, context->samplerate);
|
||||||
goto error;
|
if (handle->handler) {
|
||||||
}
|
context->stream_url = switch_core_sprintf(context->memory_pool, "http://%s", path);
|
||||||
*host++ = '\0';
|
launch_stream_thread(context);
|
||||||
|
|
||||||
if ((file = strchr(host, '/'))) {
|
|
||||||
*file++ = '\0';
|
|
||||||
} else {
|
} else {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL: %s\n", path);
|
if (switch_file_open(&context->fd, path, SWITCH_FOPEN_READ,
|
||||||
|
SWITCH_FPROT_UREAD|SWITCH_FPROT_UWRITE, handle->memory_pool) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
||||||
|
if (!(context->gfp = lame_init())) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_set_host(context->shout, host) != SHOUTERR_SUCCESS) {
|
lame_set_num_channels(context->gfp, handle->channels);
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting hostname: %s\n", shout_get_error(context->shout));
|
lame_set_in_samplerate(context->gfp, handle->samplerate);
|
||||||
goto error;
|
lame_set_brate(context->gfp, 24);
|
||||||
}
|
lame_set_mode(context->gfp, 3);
|
||||||
|
lame_set_quality(context->gfp, 2); /* 2=high 5 = medium 7=low */
|
||||||
if (shout_set_protocol(context->shout, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting protocol: %s\n", shout_get_error(context->shout));
|
lame_set_errorf(context->gfp, log_error);
|
||||||
goto error;
|
lame_set_debugf(context->gfp, log_debug);
|
||||||
}
|
lame_set_msgf(context->gfp, log_msg);
|
||||||
|
|
||||||
|
lame_init_params(context->gfp);
|
||||||
|
lame_print_config(context->gfp);
|
||||||
|
|
||||||
|
if (handle->handler) {
|
||||||
|
lame_set_bWriteVbrTag(context->gfp, 0);
|
||||||
|
lame_mp3_tags_fid(context->gfp, NULL);
|
||||||
|
|
||||||
|
username = switch_core_strdup(handle->memory_pool, path);
|
||||||
|
if (!(password = strchr(username, ':'))) {
|
||||||
|
err = "invalid url";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
*password++ = '\0';
|
||||||
|
|
||||||
|
if (!(host = strchr(password, '@'))) {
|
||||||
|
err = "invalid url";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
*host++ = '\0';
|
||||||
|
|
||||||
if (shout_set_port(context->shout, 8000) != SHOUTERR_SUCCESS) {
|
if ((file = strchr(host, '/'))) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting port: %s\n", shout_get_error(context->shout));
|
*file++ = '\0';
|
||||||
goto error;
|
} else {
|
||||||
}
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL: %s\n", path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(context->shout = shout_new())) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate shout_t\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shout_set_host(context->shout, host) != SHOUTERR_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting hostname: %s\n", shout_get_error(context->shout));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (shout_set_password(context->shout, password) != SHOUTERR_SUCCESS) {
|
if (shout_set_protocol(context->shout, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting password: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting protocol: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shout_set_port(context->shout, 8000) != SHOUTERR_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting port: %s\n", shout_get_error(context->shout));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (shout_set_mount(context->shout, file) != SHOUTERR_SUCCESS) {
|
if (shout_set_password(context->shout, password) != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting mount: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting password: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_set_user(context->shout, username) != SHOUTERR_SUCCESS) {
|
if (shout_set_mount(context->shout, file) != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting mount: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_set_url(context->shout, "mod_shout") != SHOUTERR_SUCCESS) {
|
if (shout_set_user(context->shout, username) != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting name: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_set_audio_info(context->shout, "bitrate", "24000") != SHOUTERR_SUCCESS) {
|
if (shout_set_url(context->shout, "mod_shout") != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting name: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_set_format(context->shout, SHOUT_FORMAT_MP3) != SHOUTERR_SUCCESS) {
|
if (shout_set_audio_info(context->shout, "bitrate", "24000") != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shout_open(context->shout) != SHOUTERR_SUCCESS) {
|
if (shout_set_format(context->shout, SHOUT_FORMAT_MP3) != SHOUTERR_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening stream: %s\n", shout_get_error(context->shout));
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout));
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shout_open(context->shout) != SHOUTERR_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening stream: %s\n", shout_get_error(context->shout));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* lame being lame and all has FILE * coded into it's API for some functions so we gotta use it */
|
||||||
|
if (!(context->fp = fopen(path, "wb+"))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
|
||||||
|
return SWITCH_STATUS_GENERR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,13 +605,19 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data,
|
|||||||
|
|
||||||
*len = 0;
|
*len = 0;
|
||||||
|
|
||||||
switch_mutex_lock(context->audio_mutex);
|
if (context->fd) {
|
||||||
if (context->audio_buffer) {
|
rb = decode_fd(context, data, bytes);
|
||||||
rb = switch_buffer_read(context->audio_buffer, data, bytes);
|
|
||||||
} else {
|
} else {
|
||||||
context->err++;
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
if (context->audio_buffer) {
|
||||||
|
rb = switch_buffer_read(context->audio_buffer, data, bytes);
|
||||||
|
} else {
|
||||||
|
switch_mutex_lock(context->audio_mutex);
|
||||||
|
context->err++;
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
|
}
|
||||||
|
switch_mutex_unlock(context->audio_mutex);
|
||||||
}
|
}
|
||||||
switch_mutex_unlock(context->audio_mutex);
|
|
||||||
|
|
||||||
if (context->err) {
|
if (context->err) {
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
@ -449,27 +636,33 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data,
|
|||||||
static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data, size_t *len)
|
static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data, size_t *len)
|
||||||
{
|
{
|
||||||
shout_context_t *context = handle->private_info;
|
shout_context_t *context = handle->private_info;
|
||||||
|
|
||||||
|
|
||||||
unsigned char mp3buf[2048] = "";
|
unsigned char mp3buf[2048] = "";
|
||||||
long ret = 0;
|
long ret = 0;
|
||||||
int rlen;
|
int rlen;
|
||||||
int16_t *audio = data;
|
int16_t *audio = data;
|
||||||
int nsamples = *len;
|
int nsamples = *len;
|
||||||
|
|
||||||
|
assert(context->gfp);
|
||||||
|
|
||||||
if ((rlen = lame_encode_buffer(context->gfp, audio, NULL, nsamples, mp3buf, sizeof(mp3buf))) < 0) {
|
if ((rlen = lame_encode_buffer(context->gfp, audio, NULL, nsamples, mp3buf, sizeof(mp3buf))) < 0) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen);
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen);
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rlen) {
|
if (handle->handler) {
|
||||||
ret = shout_send(context->shout, mp3buf, rlen);
|
if (rlen) {
|
||||||
if (ret != SHOUTERR_SUCCESS) {
|
ret = shout_send(context->shout, mp3buf, rlen);
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Send error: %s\n", shout_get_error(context->shout));
|
if (ret != SHOUTERR_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Send error: %s\n", shout_get_error(context->shout));
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shout_sync(context->shout);
|
||||||
|
} else {
|
||||||
|
if (fwrite(mp3buf, 1, rlen, context->fp) < 0) {
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shout_sync(context->shout);
|
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -530,6 +723,7 @@ static switch_loadable_module_interface_t shout_module_interface = {
|
|||||||
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
|
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
|
||||||
{
|
{
|
||||||
supported_formats[0] = "shout";
|
supported_formats[0] = "shout";
|
||||||
|
supported_formats[1] = "mp3";
|
||||||
shout_file_interface.extens = supported_formats;
|
shout_file_interface.extens = supported_formats;
|
||||||
|
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef DEBUG_MP3
|
#ifdef DEBUG_MP3
|
||||||
#define debug_printf(fmt,...) printf(fmt, ##__VA_ARGS__);
|
#define debug_printf(fmt,...) printf(fmt, ##__VA_ARGS__);
|
||||||
#else
|
#else
|
||||||
#define debug_printf;
|
#define debug_printf(fmt,...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct buf {
|
struct buf {
|
||||||
@ -47,10 +47,10 @@ struct mpstr {
|
|||||||
#define MP3_ERR -1
|
#define MP3_ERR -1
|
||||||
#define MP3_OK 0
|
#define MP3_OK 0
|
||||||
#define MP3_NEED_MORE 1
|
#define MP3_NEED_MORE 1
|
||||||
|
#define MP3_TOOSMALL 2
|
||||||
|
|
||||||
void InitMP3Constants(void);
|
void InitMP3Constants(void);
|
||||||
BOOL InitMP3(struct mpstr *mp, long outscale);
|
BOOL InitMP3(struct mpstr *mp, long outscale, int samplerate);
|
||||||
int decodeMP3(struct mpstr *mp,char *inmemory,int inmemsize,
|
int decodeMP3(struct mpstr *mp,char *inmemory,int inmemsize,
|
||||||
char *outmemory,int outmemsize,int *done);
|
char *outmemory,int outmemsize,int *done);
|
||||||
void ExitMP3(struct mpstr *mp);
|
void ExitMP3(struct mpstr *mp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user