1/* 2** Copyright (C) 2006-2016 Erik de Castro Lopo <erikd@mega-nerd.com> 3** Copyright (C) 2006 Paul Davis <paul@linuxaudiosystems.com> 4** 5** This program is free software; you can redistribute it and/or modify 6** it under the terms of the GNU Lesser General Public License as published by 7** the Free Software Foundation; either version 2.1 of the License, or 8** (at your option) any later version. 9** 10** This program is distributed in the hope that it will be useful, 11** but WITHOUT ANY WARRANTY; without even the implied warranty of 12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13** GNU Lesser General Public License for more details. 14** 15** You should have received a copy of the GNU Lesser General Public License 16** along with this program; if not, write to the Free Software 17** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18*/ 19 20#include "sfconfig.h" 21 22#include <stdio.h> 23#include <stddef.h> 24#include <string.h> 25 26#include "common.h" 27 28 29static int gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) ; 30 31static inline size_t 32bc_min_size (const SF_BROADCAST_INFO* info) 33{ if (info == NULL) 34 return 0 ; 35 36 return offsetof (SF_BROADCAST_INFO, coding_history) + info->coding_history_size ; 37} /* bc_min_size */ 38 39SF_BROADCAST_INFO_16K* 40broadcast_var_alloc (void) 41{ return calloc (1, sizeof (SF_BROADCAST_INFO_16K)) ; 42} /* broadcast_var_alloc */ 43 44int 45broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * info, size_t datasize) 46{ size_t len ; 47 48 if (info == NULL) 49 return SF_FALSE ; 50 51 if (bc_min_size (info) > datasize) 52 { psf->error = SFE_BAD_BROADCAST_INFO_SIZE ; 53 return SF_FALSE ; 54 } ; 55 56 if (datasize >= sizeof (SF_BROADCAST_INFO_16K)) 57 { psf->error = SFE_BAD_BROADCAST_INFO_TOO_BIG ; 58 return SF_FALSE ; 59 } ; 60 61 if (psf->broadcast_16k == NULL) 62 { if ((psf->broadcast_16k = broadcast_var_alloc ()) == NULL) 63 { psf->error = SFE_MALLOC_FAILED ; 64 return SF_FALSE ; 65 } ; 66 } ; 67 68 /* Only copy the first part of the struct. */ 69 memcpy (psf->broadcast_16k, info, offsetof (SF_BROADCAST_INFO, coding_history)) ; 70 71 psf_strlcpy_crlf (psf->broadcast_16k->coding_history, info->coding_history, sizeof (psf->broadcast_16k->coding_history), datasize - offsetof (SF_BROADCAST_INFO, coding_history)) ; 72 len = strlen (psf->broadcast_16k->coding_history) ; 73 74 if (len > 0 && psf->broadcast_16k->coding_history [len - 1] != '\n') 75 psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), "\r\n") ; 76 77 if (psf->file.mode == SFM_WRITE) 78 { char added_history [256] ; 79 80 gen_coding_history (added_history, sizeof (added_history), &(psf->sf)) ; 81 psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), added_history) ; 82 } ; 83 84 /* Force coding_history_size to be even. */ 85 len = strlen (psf->broadcast_16k->coding_history) ; 86 len += (len & 1) ? 1 : 0 ; 87 psf->broadcast_16k->coding_history_size = (uint32_t) len ; 88 89 /* Currently writing this version. */ 90 psf->broadcast_16k->version = 2 ; 91 92 return SF_TRUE ; 93} /* broadcast_var_set */ 94 95 96int 97broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) 98{ size_t size ; 99 100 if (psf->broadcast_16k == NULL) 101 return SF_FALSE ; 102 103 size = SF_MIN (datasize, bc_min_size ((const SF_BROADCAST_INFO *) psf->broadcast_16k)) ; 104 105 memcpy (data, psf->broadcast_16k, size) ; 106 107 return SF_TRUE ; 108} /* broadcast_var_get */ 109 110/*------------------------------------------------------------------------------ 111*/ 112 113static int 114gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) 115{ char chnstr [16] ; 116 int count, width ; 117 118 /* 119 ** From : http://www.sr.se/utveckling/tu/bwf/docs/codhist2.htm 120 ** 121 ** Parameter Variable string <allowed option> Unit 122 ** ========================================================================================== 123 ** Coding Algorithm A=<ANALOGUE, PCM, MPEG1L1, MPEG1L2, MPEG1L3, 124 ** MPEG2L1, MPEG2L2, MPEG2L3> 125 ** Sampling frequency F=<11000,22050,24000,32000,44100,48000> [Hz] 126 ** Bit-rate B=<any bit-rate allowed in MPEG 2 (ISO/IEC [kbit/s per channel] 127 ** 13818-3)> 128 ** Word Length W=<8, 12, 14, 16, 18, 20, 22, 24> [bits] 129 ** Mode M=<mono, stereo, dual-mono, joint-stereo> 130 ** Text, free string T=<a free ASCII-text string for in house use. 131 ** This string should contain no commas (ASCII 132 ** 2Chex). Examples of the contents: ID-No; codec 133 ** type; A/D type> 134 */ 135 136 switch (psfinfo->channels) 137 { case 0 : 138 return SF_FALSE ; 139 140 case 1 : 141 psf_strlcpy (chnstr, sizeof (chnstr), "mono") ; 142 break ; 143 144 case 2 : 145 psf_strlcpy (chnstr, sizeof (chnstr), "stereo") ; 146 break ; 147 148 default : 149 snprintf (chnstr, sizeof (chnstr), "%dchn", psfinfo->channels) ; 150 break ; 151 } ; 152 153 switch (SF_CODEC (psfinfo->format)) 154 { case SF_FORMAT_PCM_U8 : 155 case SF_FORMAT_PCM_S8 : 156 width = 8 ; 157 break ; 158 case SF_FORMAT_PCM_16 : 159 width = 16 ; 160 break ; 161 case SF_FORMAT_PCM_24 : 162 width = 24 ; 163 break ; 164 case SF_FORMAT_PCM_32 : 165 width = 32 ; 166 break ; 167 case SF_FORMAT_FLOAT : 168 width = 24 ; /* Bits in the mantissa + 1 */ 169 break ; 170 case SF_FORMAT_DOUBLE : 171 width = 53 ; /* Bits in the mantissa + 1 */ 172 break ; 173 case SF_FORMAT_ULAW : 174 case SF_FORMAT_ALAW : 175 width = 12 ; 176 break ; 177 default : 178 width = 42 ; 179 break ; 180 } ; 181 182 count = snprintf (added_history, added_history_max, 183 "A=PCM,F=%d,W=%d,M=%s,T=%s-%s\r\n", 184 psfinfo->samplerate, width, chnstr, PACKAGE_NAME, PACKAGE_VERSION) ; 185 186 if (count >= added_history_max) 187 return 0 ; 188 189 return count ; 190} /* gen_coding_history */ 191