1 /* 2 * Copyright (C) 2008 iptego GmbH 3 * 4 * This file is part of SEMS, a free SIP media server. 5 * 6 * SEMS is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. This program is released under 10 * the GPL with the additional exemption that compiling, linking, 11 * and/or using OpenSSL is allowed. 12 * 13 * For a license to use the SEMS software under conditions 14 * other than those described here, or to purchase support for this 15 * software, please contact iptel.org by e-mail at the following addresses: 16 * info@iptel.org 17 * 18 * SEMS is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 */ 27 28 #include "AmPrecodedFile.h" 29 #include "AmUtils.h" 30 #include "log.h" 31 #include <fstream> 32 33 #include <libgen.h> 34 35 unsigned int precoded_bytes2samples(long h_codec, unsigned int num_bytes) { 36 37 return ((precoded_payload_t*)h_codec)->frame_ms 38 * ((precoded_payload_t*)h_codec)->sample_rate 39 / 1000; 40 } 41 42 unsigned int precoded_samples2bytes(long h_codec, unsigned int num_samples) { 43 return ((precoded_payload_t*)h_codec)->frame_bytes; 44 } 45 46 amci_codec_t _codec_precoded = { 47 PRECODED_CODEC_ID, 48 NULL, 49 NULL, 50 NULL, 51 NULL, 52 NULL, 53 precoded_bytes2samples, 54 precoded_samples2bytes, 55 NULL 56 }; 57 58 void AmPrecodedFile::initPlugin() { 59 AmPlugIn::instance()->addCodec(&_codec_precoded); AmPayloadProvider()60 for(std::map<int,precoded_payload_t>::iterator it = 61 payloads.begin(); it != payloads.end(); ++it) 62 AmPlugIn::instance()->addPayload(&it->second); 63 } 64 65 AmPrecodedRtpFormat::AmPrecodedRtpFormat(precoded_payload_t& precoded_payload) 66 : AmAudioRtpFormat(), precoded_payload(precoded_payload) 67 { 68 channels = precoded_payload.channels; 69 rate = precoded_payload.sample_rate; 70 // frame_size is in samples, precoded_payload.frame_size in millisec 71 //frame_size = precoded_payload.frame_ms * precoded_payload.sample_rate / 1000; 72 //frame_length = precoded_payload.frame_ms; 73 //frame_encoded_size = precoded_payload.frame_bytes; 74 h_codec = (long)&(this->precoded_payload); 75 } 76 77 AmPrecodedRtpFormat::~AmPrecodedRtpFormat() { 78 } 79 80 AmPrecodedFileFormat::AmPrecodedFileFormat(precoded_payload_t& precoded_payload) 81 : AmAudioFileFormat(""), precoded_payload(precoded_payload) 82 { 83 subtype.type = 0; 84 subtype.name = precoded_payload.name; 85 subtype.sample_rate = precoded_payload.sample_rate; 86 subtype.channels = precoded_payload.channels; 87 subtype.codec_id = PRECODED_CODEC_ID; 88 89 channels = precoded_payload.channels; 90 rate = precoded_payload.sample_rate; 91 codec = getCodec(); 92 93 // used in precoded_bytes2samples()/precoded_samples2bytes() 94 //frame_size = precoded_payload.frame_ms * precoded_payload.sample_rate / 1000; 95 //frame_encoded_size = precoded_payload.frame_bytes; 96 h_codec = (long)&(this->precoded_payload); 97 } 98 99 AmPrecodedFileFormat::~AmPrecodedFileFormat() { 100 } 101 102 int precoded_file_open(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, long h_codec) 103 { 104 fseek (fp, 0, SEEK_END); 105 fmt_desc->data_size=ftell (fp); 106 rewind(fp); 107 DBG("file opened, size = %d\n", fmt_desc->data_size); 108 return 0; 109 } 110 111 int precoded_file_close(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, 112 long h_codec, struct amci_codec_t *codec) 113 { 114 DBG("file closed\n"); 115 return 0; 116 } 117 118 AmPrecodedFileInstance::AmPrecodedFileInstance(precoded_payload_t& precoded_payload) 119 : AmAudioFile(), precoded_payload(precoded_payload) 120 { 121 memset(&m_iofmt, 0, sizeof(amci_inoutfmt_t)); 122 m_iofmt.open = &precoded_file_open; 123 m_iofmt.on_close = &precoded_file_close; 124 iofmt = &m_iofmt; 125 } 126 127 AmPrecodedFileInstance::~AmPrecodedFileInstance(){ 128 } 129 130 AmAudioFileFormat* AmPrecodedFileInstance::fileName2Fmt(const string& name, const string& subtype) { 131 return new AmPrecodedFileFormat(precoded_payload); 132 } 133 134 int AmPrecodedFileInstance::open() { 135 return AmAudioFile::open(precoded_payload.filename, AmAudioFile::Read); 136 } 137 138 AmPrecodedRtpFormat* AmPrecodedFileInstance::getRtpFormat() { 139 return new AmPrecodedRtpFormat(precoded_payload); 140 } 141 142 AmPrecodedFile::AmPrecodedFile() 143 { 144 } 145 146 AmPrecodedFile::~AmPrecodedFile() { 147 } 148 149 int AmPrecodedFile::open(const std::string& filename) { 150 std::ifstream ifs(filename.c_str()); 151 if (!ifs.good()) { 152 return -1; 153 } 154 155 char *dir = strdup(filename.c_str()); 156 string str_dir(dirname(dir)); 157 str_dir += "/"; 158 159 while (ifs.good() && !ifs.eof()) { 160 string codec_line; 161 getline(ifs, codec_line); 162 if (!codec_line.length() || codec_line[0]=='#') 163 continue; 164 165 vector<string> codec_def = explode(codec_line, ";"); 166 if (codec_def.size() != 8) { 167 ERROR("unable to decipher codec line '%s'\n", 168 codec_line.c_str()); 169 continue; 170 } 171 172 precoded_payload_t pl; 173 174 #define get_uint_item(name, index, description) \ 175 unsigned int name; \ 176 if (str2i(codec_def[index], name)) { \ 177 ERROR("decoding " description " in codec line '%s'\n", \ 178 codec_line.c_str()); \ 179 continue; \ 180 } \ 181 pl.name = name; 182 183 get_uint_item(payload_id, 0, "payload_id"); 184 pl.c_name = codec_def[1]; 185 pl.name = pl.c_name.c_str(); 186 get_uint_item(sample_rate, 2, "sample_rate"); 187 get_uint_item(channels, 3, "channels"); 188 pl.format_parameters = codec_def[4]; 189 get_uint_item(frame_ms, 5, "frame ms"); 190 get_uint_item(frame_bytes, 6, "frame bytes"); 191 pl.filename=str_dir + codec_def[7]; 192 #undef get_uint_item 193 194 DBG("inserting codec '%s' file '%s' and id %d\n", 195 pl.name, pl.filename.c_str(), pl.payload_id); 196 payloads[pl.payload_id]=pl; 197 } 198 free(dir); 199 ifs.close(); 200 return 0; // OK 201 } 202 203 amci_payload_t* AmPrecodedFile::payload(int payload_id) const { 204 std::map<int,precoded_payload_t>::const_iterator it = 205 payloads.find(payload_id); 206 207 if(it != payloads.end()) 208 return (amci_payload_t*)&it->second; 209 210 return NULL; 211 } 212 213 int AmPrecodedFile::getDynPayload(const string& name, int rate, int encoding_param) const { 214 // find a dynamic payload by name/rate and encoding_param (channels, if > 0) 215 for(std::map<int, precoded_payload_t>::const_iterator pl_it = payloads.begin(); 216 pl_it != payloads.end(); ++pl_it) 217 if( (name == pl_it->second.name) 218 && (rate == pl_it->second.sample_rate) ) { 219 if ((encoding_param > 0) && (pl_it->second.channels > 0) && 220 (encoding_param != pl_it->second.channels)) 221 continue; 222 223 return pl_it->first; 224 } 225 226 // not found 227 return -1; 228 } 229 230 231 void AmPrecodedFile::getPayloads(vector<SdpPayload>& pl_vec) const 232 { 233 for(std::map<int,precoded_payload_t>::const_iterator pl_it = payloads.begin(); 234 pl_it != payloads.end(); ++pl_it) { 235 pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second.name, pl_it->second.sample_rate, 0)); 236 } 237 } 238 239 AmPrecodedFileInstance* AmPrecodedFile::getFileInstance(int payload_id) { 240 std::map<int,precoded_payload_t>::iterator it=payloads.find(payload_id); 241 if (it != payloads.end()) 242 return new AmPrecodedFileInstance(it->second); 243 return NULL; 244 } 245