• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 
19 #include <media/stagefright/HTTPStream.h>
20 #include <media/stagefright/MediaBuffer.h>
21 #include <media/stagefright/MediaBufferGroup.h>
22 #include <media/stagefright/MediaDebug.h>
23 #include <media/stagefright/MediaDefs.h>
24 #include <media/stagefright/MetaData.h>
25 #include <media/stagefright/ShoutcastSource.h>
26 #include <media/stagefright/stagefright_string.h>
27 
28 namespace android {
29 
ShoutcastSource(HTTPStream * http)30 ShoutcastSource::ShoutcastSource(HTTPStream *http)
31     : mHttp(http),
32       mMetaDataOffset(0),
33       mBytesUntilMetaData(0),
34       mGroup(NULL),
35       mStarted(false) {
36     string metaint;
37     if (mHttp->find_header_value("icy-metaint", &metaint)) {
38         char *end;
39         const char *start = metaint.c_str();
40         mMetaDataOffset = strtol(start, &end, 10);
41         CHECK(end > start && *end == '\0');
42         CHECK(mMetaDataOffset > 0);
43 
44         mBytesUntilMetaData = mMetaDataOffset;
45     }
46 }
47 
~ShoutcastSource()48 ShoutcastSource::~ShoutcastSource() {
49     if (mStarted) {
50         stop();
51     }
52 
53     delete mHttp;
54     mHttp = NULL;
55 }
56 
start(MetaData *)57 status_t ShoutcastSource::start(MetaData *) {
58     CHECK(!mStarted);
59 
60     mGroup = new MediaBufferGroup;
61     mGroup->add_buffer(new MediaBuffer(4096));  // XXX
62 
63     mStarted = true;
64 
65     return OK;
66 }
67 
stop()68 status_t ShoutcastSource::stop() {
69     CHECK(mStarted);
70 
71     delete mGroup;
72     mGroup = NULL;
73 
74     mStarted = false;
75 
76     return OK;
77 }
78 
getFormat()79 sp<MetaData> ShoutcastSource::getFormat() {
80     sp<MetaData> meta = new MetaData;
81     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
82     meta->setInt32(kKeySampleRate, 44100);
83     meta->setInt32(kKeyChannelCount, 2);  // XXX
84 
85     return meta;
86 }
87 
read(MediaBuffer ** out,const ReadOptions * options)88 status_t ShoutcastSource::read(
89         MediaBuffer **out, const ReadOptions *options) {
90     CHECK(mStarted);
91 
92     *out = NULL;
93 
94     int64_t seekTimeUs;
95     if (options && options->getSeekTo(&seekTimeUs)) {
96         return ERROR_UNSUPPORTED;
97     }
98 
99     MediaBuffer *buffer;
100     status_t err = mGroup->acquire_buffer(&buffer);
101     if (err != OK) {
102         return err;
103     }
104 
105     *out = buffer;
106 
107     size_t num_bytes = buffer->size();
108     if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
109         num_bytes = mBytesUntilMetaData;
110     }
111 
112     ssize_t n = mHttp->receive(buffer->data(), num_bytes);
113 
114     if (n <= 0) {
115         return (status_t)n;
116     }
117 
118     buffer->set_range(0, n);
119 
120     mBytesUntilMetaData -= (size_t)n;
121 
122     if (mBytesUntilMetaData == 0) {
123         unsigned char num_16_byte_blocks = 0;
124         n = mHttp->receive((char *)&num_16_byte_blocks, 1);
125         CHECK_EQ(n, 1);
126 
127         char meta[255 * 16];
128         size_t meta_size = num_16_byte_blocks * 16;
129         size_t meta_length = 0;
130         while (meta_length < meta_size) {
131             n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
132             if (n <= 0) {
133                 return (status_t)n;
134             }
135 
136             meta_length += (size_t) n;
137         }
138 
139         while (meta_length > 0 && meta[meta_length - 1] == '\0') {
140             --meta_length;
141         }
142 
143         if (meta_length > 0) {
144             // Technically we should probably attach this meta data to the
145             // next buffer. XXX
146             buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
147         }
148 
149         mBytesUntilMetaData = mMetaDataOffset;
150     }
151 
152     return OK;
153 }
154 
155 }  // namespace android
156 
157