format.c 4.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org, 
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
 */

13
/* -*- c-basic-offset: 4; -*- */
Jack Moffitt's avatar
Jack Moffitt committed
14
15
16
17
18
19
/* format.c
**
** format plugin implementation
**
*/

20
21
22
23
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Jack Moffitt's avatar
Jack Moffitt committed
24
25
#include <stdlib.h>
#include <string.h>
Karl Heyes's avatar
Karl Heyes committed
26
27
28
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
29
#include <time.h>
Jack Moffitt's avatar
Jack Moffitt committed
30
31
32
33

#include "connection.h"
#include "refbuf.h"

Michael Smith's avatar
Michael Smith committed
34
#include "source.h"
Jack Moffitt's avatar
Jack Moffitt committed
35
#include "format.h"
36
#include "global.h"
Karl Heyes's avatar
Karl Heyes committed
37
#include "httpp/httpp.h"
Jack Moffitt's avatar
Jack Moffitt committed
38
39

#include "format_vorbis.h"
Michael Smith's avatar
Michael Smith committed
40
#include "format_mp3.h"
Jack Moffitt's avatar
Jack Moffitt committed
41

42
43
#include "logging.h"
#define CATMODULE "format"
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
44
45
46
47
48

#ifdef WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
49

Michael Smith's avatar
Michael Smith committed
50
51
52
format_type_t format_get_type(char *contenttype)
{
    if(strcmp(contenttype, "application/x-ogg") == 0)
53
54
55
        return FORMAT_TYPE_VORBIS; /* Backwards compatibility */
    else if(strcmp(contenttype, "application/ogg") == 0)
        return FORMAT_TYPE_VORBIS; /* Now blessed by IANA */
Michael Smith's avatar
Michael Smith committed
56
57
    else if(strcmp(contenttype, "audio/mpeg") == 0)
        return FORMAT_TYPE_MP3; 
58
59
    else if(strcmp(contenttype, "audio/x-mpeg") == 0)
        return FORMAT_TYPE_MP3; /* Relay-compatibility for some servers */
Michael Smith's avatar
Michael Smith committed
60
    else
61
        return FORMAT_ERROR;
Michael Smith's avatar
Michael Smith committed
62
63
}

64
65
66
67
char *format_get_mimetype(format_type_t type)
{
    switch(type) {
        case FORMAT_TYPE_VORBIS:
68
            return "application/ogg";
69
70
71
72
73
74
75
76
77
            break;
        case FORMAT_TYPE_MP3:
            return "audio/mpeg";
            break;
        default:
            return NULL;
    }
}

78
79
format_plugin_t *format_get_plugin(format_type_t type, char *mount, 
        http_parser_t *parser)
Jack Moffitt's avatar
Jack Moffitt committed
80
{
81
    format_plugin_t *plugin;
Jack Moffitt's avatar
Jack Moffitt committed
82

83
84
85
86
87
    switch (type) {
    case FORMAT_TYPE_VORBIS:
        plugin = format_vorbis_get_plugin();
        if (plugin) plugin->mount = mount;
        break;
Michael Smith's avatar
Michael Smith committed
88
    case FORMAT_TYPE_MP3:
89
        plugin = format_mp3_get_plugin(parser);
Michael Smith's avatar
Michael Smith committed
90
91
        if (plugin) plugin->mount = mount;
        break;
92
93
94
95
    default:
        plugin = NULL;
        break;
    }
Jack Moffitt's avatar
Jack Moffitt committed
96

97
    return plugin;
Jack Moffitt's avatar
Jack Moffitt committed
98
}
99
100
101
102
103

int format_generic_write_buf_to_client(format_plugin_t *format, 
        client_t *client, unsigned char *buf, int len)
{
    int ret;
104

105
106
107
    ret = sock_write_bytes(client->con->sock, buf, len);

    if(ret < 0) {
108
        if(sock_recoverable(sock_error())) {
109
110
111
112
113
114
115
116
117
118
            DEBUG1("Client had recoverable error %ld", ret);
            ret = 0;
        }
    }
    else
        client->con->sent_bytes += ret;

    return ret;
}

Michael Smith's avatar
Michael Smith committed
119
120
121
122
123
124
125
void format_send_general_headers(format_plugin_t *format,
        source_t *source, client_t *client)
{
    http_var_t *var;
    avl_node *node;
    int bytes;

126
127
128
    /* iterate through source http headers and send to client */
    avl_tree_rlock(source->parser->vars);
    node = avl_get_first(source->parser->vars);
Karl Heyes's avatar
Karl Heyes committed
129
130
    while (node)
    {
131
        var = (http_var_t *)node->key;
Karl Heyes's avatar
Karl Heyes committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
        if (!strcasecmp(var->name, "ice-audio-info")) {
            /* convert ice-audio-info to icy-br */
            char *brfield;
            unsigned int bitrate;

            brfield = strstr(var->value, "bitrate=");
            if (brfield && sscanf(var->value, "bitrate=%u", &bitrate)) {
                bytes = sock_write(client->con->sock, "icy-br:%u\r\n", bitrate);
                if (bytes > 0)
                    client->con->sent_bytes += bytes;
            }
        }
        else
        {
            if (strcasecmp(var->name, "ice-password") &&
                strcasecmp(var->name, "icy-metaint"))
            {
                bytes = 0;
                if (!strncasecmp("ice-", var->name, 4))
                {
                    if (!strcasecmp("ice-bitrate", var->name))
                        bytes += sock_write(client->con->sock, "icy-br:%s\r\n", var->value);
                    else
155
156
157
158
159
160
                        if (!strcasecmp("ice-public", var->name))
                            bytes += sock_write(client->con->sock, 
                                "icy-pub:%s\r\n", var->value);
                        else
                            bytes = sock_write(client->con->sock, "icy%s:%s\r\n",
                                var->name + 3, var->value);
Karl Heyes's avatar
Karl Heyes committed
161
162
163
164
165
166
167
168
169
170
                            
                }
                if (!strncasecmp("icy-", var->name, 4))
                {
                    bytes = sock_write(client->con->sock, "icy%s:%s\r\n",
                            var->name + 3, var->value);
                }
                if (bytes > 0)
                    client->con->sent_bytes += bytes;
            }
171
172
173
174
        }
        node = avl_get_next(node);
    }
    avl_tree_unlock(source->parser->vars);
175
176
177
    bytes = sock_write(client->con->sock,
            "Server: %s\r\n", ICECAST_VERSION_STRING);
    if(bytes > 0) client->con->sent_bytes += bytes;
Michael Smith's avatar
Michael Smith committed
178
179
}