format_mp3.c 17.4 KB
Newer Older
1
/* -*- c-basic-offset: 4; -*- */
2
3
4
5
6
7
8
9
10
11
12
13
/* 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).
 */

Michael Smith's avatar
Michael Smith committed
14
15
/* format_mp3.c
**
Michael Smith's avatar
Michael Smith committed
16
** format plugin for mp3
Michael Smith's avatar
Michael Smith committed
17
18
19
**
*/

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

Michael Smith's avatar
Michael Smith committed
24
25
26
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Karl Heyes's avatar
Karl Heyes committed
27
28
29
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
Michael Smith's avatar
Michael Smith committed
30
31

#include "refbuf.h"
Michael Smith's avatar
Michael Smith committed
32
33
#include "source.h"
#include "client.h"
Michael Smith's avatar
Michael Smith committed
34
35
36

#include "stats.h"
#include "format.h"
Michael Smith's avatar
Michael Smith committed
37
38
39
40
41
42
#include "httpp/httpp.h"

#include "logging.h"

#include "format_mp3.h"

Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
43
44
45
#ifdef WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
46
#define snprintf _snprintf
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
47
48
#endif

Michael Smith's avatar
Michael Smith committed
49
50
#define CATMODULE "format-mp3"

51
52
53
/* Note that this seems to be 8192 in shoutcast - perhaps we want to be the
 * same for compability with crappy clients?
 */
Michael Smith's avatar
Michael Smith committed
54
#define ICY_METADATA_INTERVAL 16000
Michael Smith's avatar
Michael Smith committed
55

56
static void format_mp3_free_plugin(format_plugin_t *self);
Karl Heyes's avatar
Karl Heyes committed
57
58
59
60
static refbuf_t *mp3_get_filter_meta (source_t *source);
static refbuf_t *mp3_get_no_meta (source_t *source);

static int  format_mp3_create_client_data (source_t *source, client_t *client);
61
static void free_mp3_client_data (client_t *client);
Karl Heyes's avatar
Karl Heyes committed
62
static int format_mp3_write_buf_to_client(format_plugin_t *self, client_t *client);
Michael Smith's avatar
Michael Smith committed
63
64
static void format_mp3_send_headers(format_plugin_t *self, 
        source_t *source, client_t *client);
Karl Heyes's avatar
Karl Heyes committed
65
66
static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf);

Michael Smith's avatar
Michael Smith committed
67
68

typedef struct {
Michael Smith's avatar
Michael Smith committed
69
70
   int use_metadata;
   int metadata_offset;
Karl Heyes's avatar
Karl Heyes committed
71
72
73
   unsigned int since_meta_block;
   int in_metadata;
   refbuf_t *associated;
Michael Smith's avatar
Michael Smith committed
74
} mp3_client_data;
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
75

Karl Heyes's avatar
Karl Heyes committed
76
int format_mp3_get_plugin (source_t *source)
Michael Smith's avatar
Michael Smith committed
77
{
78
    char *metadata;
79
    format_plugin_t *plugin;
Michael Smith's avatar
Michael Smith committed
80
    mp3_state *state = calloc(1, sizeof(mp3_state));
Karl Heyes's avatar
Karl Heyes committed
81
    refbuf_t *meta;
Michael Smith's avatar
Michael Smith committed
82

83
    plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
Michael Smith's avatar
Michael Smith committed
84

85
    plugin->type = FORMAT_TYPE_MP3;
Karl Heyes's avatar
Karl Heyes committed
86
    plugin->get_buffer = mp3_get_no_meta;
Michael Smith's avatar
Michael Smith committed
87
    plugin->write_buf_to_client = format_mp3_write_buf_to_client;
Karl Heyes's avatar
Karl Heyes committed
88
    plugin->write_buf_to_file = write_mp3_to_file;
89
    plugin->create_client_data = format_mp3_create_client_data;
Michael Smith's avatar
Michael Smith committed
90
    plugin->client_send_headers = format_mp3_send_headers;
91
    plugin->free_plugin = format_mp3_free_plugin;
92
    plugin->format_description = "MP3 audio";
Michael Smith's avatar
Michael Smith committed
93

94
    plugin->_state = state;
Michael Smith's avatar
Michael Smith committed
95

Karl Heyes's avatar
Karl Heyes committed
96
97
98
99
    meta = refbuf_new (1);
    memcpy (meta->data, "", 1);
    state->metadata = meta;
    state->interval = ICY_METADATA_INTERVAL;
Michael Smith's avatar
Michael Smith committed
100

Karl Heyes's avatar
Karl Heyes committed
101
102
103
104
105
106
107
108
109
    metadata = httpp_getvar (source->parser, "icy-metaint");
    if (metadata)
    {
        state->inline_metadata_interval = atoi (metadata);
        state->offset = 0;
        plugin->get_buffer = mp3_get_filter_meta;
    }
    source->format = plugin;
    thread_mutex_create (&state->url_lock);
110

Karl Heyes's avatar
Karl Heyes committed
111
    return 0;
Michael Smith's avatar
Michael Smith committed
112
113
}

114

Karl Heyes's avatar
Karl Heyes committed
115
void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value)
Michael Smith's avatar
Michael Smith committed
116
{
Karl Heyes's avatar
Karl Heyes committed
117
118
119
120
121
122
123
124
125
126
127
128
129
    mp3_state *source_mp3 = plugin->_state;
    unsigned int len;
    const char meta[] = "StreamTitle='";
    int size = sizeof (meta) + 1;

    if (tag==NULL || value == NULL)
        return;

    len = strlen (value)+1;
    size += len;
    /* protect against multiple updaters */
    thread_mutex_lock (&source_mp3->url_lock);
    if (strcmp (tag, "title") == 0 || strcmp (tag, "song") == 0)
130
    {
Karl Heyes's avatar
Karl Heyes committed
131
132
        char *p = strdup (value);
        if (p)
133
        {
Karl Heyes's avatar
Karl Heyes committed
134
135
136
137
138
            free (source_mp3->url_title);
            free (source_mp3->url_artist);
            source_mp3->url_artist = NULL;
            source_mp3->url_title = p;
            source_mp3->update_metadata = 1;
139
        }
Karl Heyes's avatar
Karl Heyes committed
140
141
142
143
144
145
146
147
148
149
150
151
152
    }
    else if (strcmp (tag, "artist") == 0)
    {
        char *p = strdup (value);
        if (p)
        {
            free (source_mp3->url_artist);
            source_mp3->url_artist = p;
            source_mp3->update_metadata = 1;
        }
    }
    thread_mutex_unlock (&source_mp3->url_lock);
}
153
154


Karl Heyes's avatar
Karl Heyes committed
155
156
157
158
159
160
static void filter_shoutcast_metadata (source_t *source, char *metadata, unsigned int meta_len)
{
    if (metadata)
    {
        char *end, *p;
        int len;
161

Karl Heyes's avatar
Karl Heyes committed
162
        do
163
        {
Karl Heyes's avatar
Karl Heyes committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
            metadata++;
            if (strncmp (metadata, "StreamTitle='", 13))
                break;
            if ((end = strstr (metadata, "\';")) == NULL)
                break;
            len = (end - metadata) - 13;
            p = calloc (1, len+1);
            if (p)
            {
                memcpy (p, metadata+13, len);
                stats_event (source->mount, "title", p);
                yp_touch (source->mount);
                free (p);
            }
        } while (0);
    }
}
181

Michael Smith's avatar
Michael Smith committed
182

Karl Heyes's avatar
Karl Heyes committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/* called from the source thread when the metadata has been updated.
 * The artist title are checked and made ready for clients to send
 */
void mp3_set_title (source_t *source)
{
    const char meta[] = "StreamTitle='";
    int size;
    unsigned char len_byte;
    refbuf_t *p;
    unsigned int len = sizeof(meta) + 2; /* the StreamTitle, quotes, ; and null */
    mp3_state *source_mp3 = source->format->_state;

    /* make sure the url data does not disappear from under us */
    thread_mutex_lock (&source_mp3->url_lock);

    /* work out message length */
    if (source_mp3->url_artist)
        len += strlen (source_mp3->url_artist);
    if (source_mp3->url_title)
        len += strlen (source_mp3->url_title);
    if (source_mp3->url_artist && source_mp3->url_title)
        len += 3;
#define MAX_META_LEN 255*16
    if (len > MAX_META_LEN)
    {
        thread_mutex_unlock (&source_mp3->url_lock);
        WARN1 ("Metadata too long at %d chars", len);
        return;
    }
    /* work out the metadata len byte */
    len_byte = (len-1) / 16 + 1;
Michael Smith's avatar
Michael Smith committed
214

Karl Heyes's avatar
Karl Heyes committed
215
216
    /* now we know how much space to allocate, +1 for the len byte */
    size = len_byte * 16 + 1;
Michael Smith's avatar
Michael Smith committed
217

Karl Heyes's avatar
Karl Heyes committed
218
219
220
221
    p = refbuf_new (size);
    if (p)
    {
        mp3_state *source_mp3 = source->format->_state;
Michael Smith's avatar
Michael Smith committed
222

Karl Heyes's avatar
Karl Heyes committed
223
224
225
226
227
228
229
230
        memset (p->data, '\0', size);
        if (source_mp3->url_artist && source_mp3->url_title)
            snprintf (p->data, size, "%c%s%s - %s';", len_byte, meta,
                    source_mp3->url_artist, source_mp3->url_title);
        else
            snprintf (p->data, size, "%c%s%s';", len_byte, meta,
                    source_mp3->url_title);
        filter_shoutcast_metadata (source, p->data, size);
Michael Smith's avatar
Michael Smith committed
231

Karl Heyes's avatar
Karl Heyes committed
232
233
234
235
        refbuf_release (source_mp3->metadata);
        source_mp3->metadata = p;
    }
    thread_mutex_unlock (&source_mp3->url_lock);
Michael Smith's avatar
Michael Smith committed
236
237
}

Karl Heyes's avatar
Karl Heyes committed
238
239
240
241
242
243

/* send the appropriate metadata, and return the number of bytes written
 * which is 0 or greater.  Check the client in_metadata value afterwards
 * to see if all metadata has been sent
 */
static int send_mp3_metadata (client_t *client, refbuf_t *associated)
Michael Smith's avatar
Michael Smith committed
244
{
245
    int ret = 0;
Karl Heyes's avatar
Karl Heyes committed
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
    unsigned char *metadata;
    int meta_len;
    mp3_client_data *client_mp3 = client->format_data;

    /* If there is a change in metadata then send it else
     * send a single zero value byte in its place
     */
    if (associated == client_mp3->associated)
    {
        metadata = "\0";
        meta_len = 1;
    }
    else
    {
        metadata = associated->data + client_mp3->metadata_offset;
        meta_len = associated->len - client_mp3->metadata_offset;
    }
    ret = client_send_bytes (client, metadata, meta_len);

    if (ret == meta_len)
    {
        client_mp3->associated = associated;
        client_mp3->metadata_offset = 0;
        client_mp3->in_metadata = 0;
        client_mp3->since_meta_block = 0;
        return ret;
    }
    if (ret > 0)
        client_mp3->metadata_offset += ret;
    else
        ret = 0;
    client_mp3->in_metadata = 1;

    return ret;
}


/* Handler for writing mp3 data to a client, taking into account whether
 * client has requested shoutcast style metadata updates
 */
static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *client) 
{
    int ret, written = 0;
    mp3_client_data *client_mp3 = client->format_data;
    mp3_state *source_mp3 = self->_state;
    refbuf_t *refbuf = client->refbuf;
    char *buf;
    unsigned int len;

    if (refbuf->next == NULL && client->pos == refbuf->len)
        return 0;

    /* move to the next buffer if we have finished with the current one */
    if (refbuf->next && client->pos == refbuf->len)
Michael Smith's avatar
Michael Smith committed
300
    {
Karl Heyes's avatar
Karl Heyes committed
301
302
303
        client_set_queue (client, refbuf->next);
        refbuf = client->refbuf;
    }
Michael Smith's avatar
Michael Smith committed
304

Karl Heyes's avatar
Karl Heyes committed
305
306
    buf = refbuf->data + client->pos;
    len = refbuf->len - client->pos;
Michael Smith's avatar
Michael Smith committed
307

Karl Heyes's avatar
Karl Heyes committed
308
309
310
311
312
313
314
    do
    {
        /* send any unwritten metadata to the client */
        if (client_mp3->in_metadata)
        {
            refbuf_t *associated = refbuf->associated;
            ret = send_mp3_metadata (client, associated);
Michael Smith's avatar
Michael Smith committed
315

Karl Heyes's avatar
Karl Heyes committed
316
317
318
            if (client_mp3->in_metadata)
                break;
            written += ret;
Michael Smith's avatar
Michael Smith committed
319
        }
Karl Heyes's avatar
Karl Heyes committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
        /* see if we need to send the current metadata to the client */
        if (client_mp3->use_metadata)
        {
            unsigned int remaining = source_mp3->interval -
                client_mp3->since_meta_block;

            /* sending the metadata block */
            if (remaining <= len)
            {
                /* send any mp3 before the metadata block */
                if (remaining)
                {
                    ret = client_send_bytes (client, buf, remaining);

                    if (ret > 0)
                    {
                        client_mp3->since_meta_block += ret;
                        client->pos += ret;
                    }
                    if (ret < (int)remaining)
                        break;
                    written += ret;
                }
                ret = send_mp3_metadata (client, refbuf->associated);
                if (client_mp3->in_metadata)
                    break;
                written += ret;
                /* change buf and len */
                buf += remaining;
                len -= remaining;
            }
351
        }
Karl Heyes's avatar
Karl Heyes committed
352
353
354
355
        /* write any mp3, maybe after the metadata block */
        if (len)
        {
            ret = client_send_bytes (client, buf, len);
356

Karl Heyes's avatar
Karl Heyes committed
357
358
359
360
361
362
363
364
365
366
367
            if (ret > 0)
            {
                client_mp3->since_meta_block += ret;
                client->pos += ret;
            }
            if (ret < (int)len)
                break;
            written += ret;
        }
        ret = 0;
    } while (0);
Michael Smith's avatar
Michael Smith committed
368

Karl Heyes's avatar
Karl Heyes committed
369
370
371
    if (ret > 0)
        written += ret;
    return written;
Michael Smith's avatar
Michael Smith committed
372
373
374
}

static void format_mp3_free_plugin(format_plugin_t *self)
Michael Smith's avatar
Michael Smith committed
375
{
376
    /* free the plugin instance */
Michael Smith's avatar
Michael Smith committed
377
    mp3_state *state = self->_state;
Michael Smith's avatar
Michael Smith committed
378

Karl Heyes's avatar
Karl Heyes committed
379
380
381
382
    thread_mutex_destroy (&state->url_lock);
    free (state->url_artist);
    free (state->url_title);
    refbuf_release (state->metadata);
Michael Smith's avatar
Michael Smith committed
383
    free(state);
384
    free(self);
Michael Smith's avatar
Michael Smith committed
385
386
}

Karl Heyes's avatar
Karl Heyes committed
387
388
389

/* read an mp3 stream which does not have shoutcast style metadata */
static refbuf_t *mp3_get_no_meta (source_t *source)
Michael Smith's avatar
Michael Smith committed
390
{
Karl Heyes's avatar
Karl Heyes committed
391
    int bytes;
392
    refbuf_t *refbuf;
Karl Heyes's avatar
Karl Heyes committed
393
    mp3_state *source_mp3 = source->format->_state;
394

Karl Heyes's avatar
Karl Heyes committed
395
396
397
    if ((refbuf = refbuf_new (2048)) == NULL)
        return NULL;
    bytes = sock_read_bytes (source->con->sock, refbuf->data, 2048);
398

Karl Heyes's avatar
Karl Heyes committed
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    if (bytes == 0)
    {
        INFO1 ("End of stream %s", source->mount);
        source->running = 0;
        refbuf_release (refbuf);
        return NULL;
    }
    if (source_mp3->update_metadata)
    {
        mp3_set_title (source);
        source_mp3->update_metadata = 0;
    }
    if (bytes > 0)
    {
        refbuf->len  = bytes;
        refbuf->associated = source_mp3->metadata;
        refbuf_addref (source_mp3->metadata);
        return refbuf;
    }
    refbuf_release (refbuf);
419

Karl Heyes's avatar
Karl Heyes committed
420
421
    if (!sock_recoverable (sock_error()))
        source->running = 0;
422

Karl Heyes's avatar
Karl Heyes committed
423
424
    return NULL;
}
425
426


Karl Heyes's avatar
Karl Heyes committed
427
428
429
430
431
432
433
434
435
436
437
438
/* read mp3 data with inlined metadata from the source. Filter out the
 * metadata so that the mp3 data itself is store on the queue and the
 * metadata is is associated with it
 */
static refbuf_t *mp3_get_filter_meta (source_t *source)
{
    refbuf_t *refbuf;
    format_plugin_t *plugin = source->format;
    mp3_state *source_mp3 = plugin->_state;
    unsigned char *src;
    unsigned int bytes, mp3_block;
    int ret;
439

Karl Heyes's avatar
Karl Heyes committed
440
441
    refbuf = refbuf_new (2048);
    src = refbuf->data;
442

Karl Heyes's avatar
Karl Heyes committed
443
    ret = sock_read_bytes (source->con->sock, refbuf->data, 2048);
444

Karl Heyes's avatar
Karl Heyes committed
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
    if (ret == 0)
    {
        INFO1 ("End of stream %s", source->mount);
        source->running = 0;
        refbuf_release (refbuf);
        return NULL;
    }
    if (source_mp3->update_metadata)
    {
        mp3_set_title (source);
        source_mp3->update_metadata = 0;
    }
    if (ret < 0)
    {
        refbuf_release (refbuf);
        if (sock_recoverable (sock_error()))
            return NULL; /* go back to waiting */
        INFO0 ("Error on connection from source");
        source->running = 0;
        return NULL;
    }
    /* fill the buffer with the read data */
    bytes = (unsigned int)ret;
    refbuf->len = 0;
    while (bytes > 0)
    {
        unsigned int metadata_remaining;
472

Karl Heyes's avatar
Karl Heyes committed
473
        mp3_block = source_mp3->inline_metadata_interval - source_mp3->offset;
474

Karl Heyes's avatar
Karl Heyes committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
        /* is there only enough to account for mp3 data */
        if (bytes <= mp3_block)
        {
            refbuf->len += bytes;
            source_mp3->offset += bytes;
            break;
        }
        /* we have enough data to get to the metadata
         * block, but only transfer upto it */
        if (mp3_block)
        {
            src += mp3_block;
            bytes -= mp3_block;
            refbuf->len += mp3_block;
            source_mp3->offset += mp3_block;
            continue;
        }
492

Karl Heyes's avatar
Karl Heyes committed
493
494
495
496
497
498
499
500
        /* process the inline metadata, len == 0 indicates not seen any yet */
        if (source_mp3->build_metadata_len == 0)
        {
            memset (source_mp3->build_metadata, 0,
                    sizeof (source_mp3->build_metadata));
            source_mp3->build_metadata_offset = 0;
            source_mp3->build_metadata_len = 1 + (*src * 16);
        }
501

Karl Heyes's avatar
Karl Heyes committed
502
503
504
505
506
507
508
509
510
511
512
513
514
515
        /* do we have all of the metatdata block */
        metadata_remaining = source_mp3->build_metadata_len -
            source_mp3->build_metadata_offset;
        if (bytes < metadata_remaining)
        {
            memcpy (source_mp3->build_metadata +
                    source_mp3->build_metadata_offset, src, bytes);
            source_mp3->build_metadata_offset += bytes;
            break;
        }
        /* copy all bytes except the last one, that way we 
         * know a null byte terminates the message */
        memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset,
                src, metadata_remaining-1);
516

Karl Heyes's avatar
Karl Heyes committed
517
518
519
        /* overwrite metadata in the buffer */
        bytes -= metadata_remaining;
        memmove (src, src+metadata_remaining, bytes);
520

Karl Heyes's avatar
Karl Heyes committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
        /* assign metadata if it's not 1 byte, as that indicates a change */
        if (source_mp3->build_metadata_len > 1)
        {
            refbuf_t *meta = refbuf_new (source_mp3->build_metadata_len);
            memcpy (meta->data, source_mp3->build_metadata,
                    source_mp3->build_metadata_len);

            DEBUG1("shoutcast metadata %.4080s", meta->data+1);
            if (strncmp (meta->data+1, "StreamTitle=", 12) == 0)
            {
                filter_shoutcast_metadata (source, source_mp3->build_metadata,
                        source_mp3->build_metadata_len);
                refbuf_release (source_mp3->metadata);
                source_mp3->metadata = meta;
            }
            else
            {
                ERROR0 ("Incorrect metadata format, ending stream");
                source->running = 0;
                refbuf_release (refbuf);
                return NULL;
542
543
            }
        }
Karl Heyes's avatar
Karl Heyes committed
544
545
        source_mp3->offset = 0;
        source_mp3->build_metadata_len = 0;
546
    }
Karl Heyes's avatar
Karl Heyes committed
547
548
549
550
551
    /* the data we have just read may of just been metadata */
    if (refbuf->len == 0)
    {
        refbuf_release (refbuf);
        return NULL;
552
    }
Karl Heyes's avatar
Karl Heyes committed
553
554
    refbuf->associated = source_mp3->metadata;
    refbuf_addref (source_mp3->metadata);
Michael Smith's avatar
Michael Smith committed
555

Karl Heyes's avatar
Karl Heyes committed
556
    return refbuf;
Michael Smith's avatar
Michael Smith committed
557
558
}

Karl Heyes's avatar
Karl Heyes committed
559
560

static int format_mp3_create_client_data(source_t *source, client_t *client)
Michael Smith's avatar
Michael Smith committed
561
562
563
564
{
    mp3_client_data *data = calloc(1,sizeof(mp3_client_data));
    char *metadata;

Karl Heyes's avatar
Karl Heyes committed
565
566
    if (data == NULL)
        return -1;
Michael Smith's avatar
Michael Smith committed
567

Karl Heyes's avatar
Karl Heyes committed
568
569
    client->format_data = data;
    client->free_client_data = free_mp3_client_data;
570
    metadata = httpp_getvar(client->parser, "icy-metadata");
Michael Smith's avatar
Michael Smith committed
571
    if(metadata)
Michael Smith's avatar
Michael Smith committed
572
        data->use_metadata = atoi(metadata)>0?1:0;
Michael Smith's avatar
Michael Smith committed
573

Karl Heyes's avatar
Karl Heyes committed
574
    return 0;
575
}
Michael Smith's avatar
Michael Smith committed
576

577
578
579
580
581
582
583
584

static void free_mp3_client_data (client_t *client)
{
    free (client->format_data);
    client->format_data = NULL;
}


Michael Smith's avatar
Michael Smith committed
585
586
587
588
static void format_mp3_send_headers(format_plugin_t *self,
        source_t *source, client_t *client)
{
    int bytes;
589
    mp3_client_data *mp3data = client->format_data;
Michael Smith's avatar
Michael Smith committed
590
591
    
    client->respcode = 200;
Michael Smith's avatar
Michael Smith committed
592
    /* TODO: This may need to be ICY/1.0 for shoutcast-compatibility? */
Michael Smith's avatar
Michael Smith committed
593
594
595
596
597
    bytes = sock_write(client->con->sock, 
            "HTTP/1.0 200 OK\r\n" 
            "Content-Type: %s\r\n", 
            format_get_mimetype(source->format->type));

Karl Heyes's avatar
Karl Heyes committed
598
599
    if (bytes > 0)
        client->con->sent_bytes += bytes;
Michael Smith's avatar
Michael Smith committed
600

Karl Heyes's avatar
Karl Heyes committed
601
602
    if (mp3data->use_metadata)
    {
603
        int bytes = sock_write(client->con->sock, "icy-metaint:%d\r\n", 
Michael Smith's avatar
Michael Smith committed
604
605
606
607
                ICY_METADATA_INTERVAL);
        if(bytes > 0)
            client->con->sent_bytes += bytes;
    }
Karl Heyes's avatar
Karl Heyes committed
608
    format_send_general_headers(self, source, client);
Michael Smith's avatar
Michael Smith committed
609
610
}

Karl Heyes's avatar
Karl Heyes committed
611
612
613
614
615
616
617
618
619
620
621
622
623

static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf)
{
    if (refbuf->len == 0)
        return;
    if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) < (size_t)refbuf->len)
    {
        WARN0 ("Write to dump file failed, disabling");
        fclose (source->dumpfile);
        source->dumpfile = NULL;
    }
}