Ticket #614: ticket614.patch
File ticket614.patch, 13.9 KB (added by nanang, 16 years ago) |
---|
-
pjmedia/include/pjmedia/wav_port.h
142 142 */ 143 143 144 144 145 /** 146 * WAV file writer options. 147 */ 148 enum pjmedia_file_writer_option 149 { 150 /** 151 * Tell the file writer to save the audio in PCM format. 152 */ 153 PJMEDIA_FILE_WRITE_PCM = 0, 145 154 155 /** 156 * Tell the file writer to save the audio in G711 Alaw format. 157 */ 158 PJMEDIA_FILE_WRITE_ALAW = 1, 159 160 /** 161 * Tell the file writer to save the audio in G711 Alaw format. 162 */ 163 PJMEDIA_FILE_WRITE_ULAW = 2, 164 }; 165 166 146 167 /** 147 168 * Create a media port to record streams to a WAV file. Note that the port 148 169 * must be closed properly (with #pjmedia_port_destroy()) so that the WAV … … 154 175 * @param channel_count Number of channels. 155 176 * @param samples_per_frame Number of samples per frame. 156 177 * @param bits_per_sample Number of bits per sample (eg 16). 157 * @param flags Port creation flags (must be 0 at present).178 * @param flags Port creation flags. 158 179 * @param buff_size Buffer size to be allocated. If the value is 159 180 * zero or negative, the port will use default buffer 160 181 * size (which is about 4KB). -
pjmedia/include/pjmedia/wave.h
66 66 */ 67 67 #define PJMEDIA_DATA_TAG ('a'<<24|'t'<<16|'a'<<8|'d') 68 68 69 /** 70 * Standard FACT tag to identify fact chunks. 71 */ 72 #define PJMEDIA_FACT_TAG ('t'<<24|'c'<<16|'a'<<8|'f') 69 73 74 70 75 /** 76 * Enumeration of format compression tag. 77 */ 78 typedef enum { 79 PJMEDIA_WAVE_FMT_TAG_PCM = 1, 80 PJMEDIA_WAVE_FMT_TAG_ALAW = 6, 81 PJMEDIA_WAVE_FMT_TAG_ULAW = 7 82 } pjmedia_wave_fmt_tag; 83 84 85 /** 71 86 * This file describes the simpler/canonical version of a WAVE file. 72 87 * It does not support the full RIFF format specification. 73 88 */ -
pjmedia/src/pjmedia/wav_writer.c
17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 19 #include <pjmedia/wav_port.h> 20 #include <pjmedia/alaw_ulaw.h> 20 21 #include <pjmedia/errno.h> 21 22 #include <pjmedia/wave.h> 22 23 #include <pj/assert.h> … … 29 30 30 31 #define THIS_FILE "wav_writer.c" 31 32 #define SIGNATURE PJMEDIA_PORT_SIGNATURE('F', 'W', 'R', 'T') 32 #define BYTES_PER_SAMPLE 233 33 34 34 35 35 struct file_port 36 36 { 37 37 pjmedia_port base; 38 pjmedia_wave_fmt_tag fmt_tag; 39 pj_uint16_t bytes_per_sample; 40 38 41 pj_size_t bufsize; 39 42 char *buf; 40 43 char *writepos; … … 72 75 pj_str_t name; 73 76 pj_status_t status; 74 77 75 PJ_UNUSED_ARG(flags);76 77 78 /* Check arguments. */ 78 79 PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL); 79 80 … … 96 97 fport->base.put_frame = &file_put_frame; 97 98 fport->base.on_destroy = &file_on_destroy; 98 99 100 if (flags == PJMEDIA_FILE_WRITE_ALAW) { 101 fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ALAW; 102 fport->bytes_per_sample = 1; 103 } else if (flags == PJMEDIA_FILE_WRITE_ULAW) { 104 fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ULAW; 105 fport->bytes_per_sample = 1; 106 } else { 107 fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_PCM; 108 fport->bytes_per_sample = 2; 109 } 99 110 100 111 /* Open file in write and read mode. 101 112 * We need the read mode because we'll modify the WAVE header once … … 113 124 114 125 wave_hdr.fmt_hdr.fmt = PJMEDIA_FMT_TAG; 115 126 wave_hdr.fmt_hdr.len = 16; 116 wave_hdr.fmt_hdr.fmt_tag = 1;127 wave_hdr.fmt_hdr.fmt_tag = fport->fmt_tag; 117 128 wave_hdr.fmt_hdr.nchan = (pj_int16_t)channel_count; 118 129 wave_hdr.fmt_hdr.sample_rate = sampling_rate; 119 130 wave_hdr.fmt_hdr.bytes_per_sec = sampling_rate * channel_count * 120 131 bits_per_sample / 8; 121 wave_hdr.fmt_hdr.block_align = (pj_int16_t) (channel_count * 122 bits_per_sample / 8); 123 wave_hdr.fmt_hdr.bits_per_sample = (pj_int16_t)bits_per_sample; 132 wave_hdr.fmt_hdr.block_align = fport->bytes_per_sample; 133 wave_hdr.fmt_hdr.bits_per_sample = fport->bytes_per_sample * 8; 124 134 125 135 wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG; 126 136 wave_hdr.data_hdr.len = 0; /* will be filled later */ … … 133 143 134 144 135 145 /* Write WAVE header */ 136 size = sizeof(pjmedia_wave_hdr); 137 status = pj_file_write(fport->fd, &wave_hdr, &size); 138 if (status != PJ_SUCCESS) { 139 pj_file_close(fport->fd); 140 return status; 146 if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) { 147 pjmedia_wave_subchunk fact_chunk; 148 pj_uint32_t tmp = 0; 149 150 fact_chunk.id = PJMEDIA_FACT_TAG; 151 fact_chunk.len = 4; 152 153 PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&fact_chunk); 154 155 /* Write WAVE header without DATA chunk header */ 156 size = sizeof(pjmedia_wave_hdr) - sizeof(wave_hdr.data_hdr); 157 status = pj_file_write(fport->fd, &wave_hdr, &size); 158 if (status != PJ_SUCCESS) { 159 pj_file_close(fport->fd); 160 return status; 161 } 162 163 /* Write FACT chunk if it stores compressed data */ 164 size = sizeof(fact_chunk); 165 status = pj_file_write(fport->fd, &fact_chunk, &size); 166 if (status != PJ_SUCCESS) { 167 pj_file_close(fport->fd); 168 return status; 169 } 170 size = 4; 171 status = pj_file_write(fport->fd, &tmp, &size); 172 if (status != PJ_SUCCESS) { 173 pj_file_close(fport->fd); 174 return status; 175 } 176 177 /* Write DATA chunk header */ 178 size = sizeof(wave_hdr.data_hdr); 179 status = pj_file_write(fport->fd, &wave_hdr.data_hdr, &size); 180 if (status != PJ_SUCCESS) { 181 pj_file_close(fport->fd); 182 return status; 183 } 184 } else { 185 size = sizeof(pjmedia_wave_hdr); 186 status = pj_file_write(fport->fd, &wave_hdr, &size); 187 if (status != PJ_SUCCESS) { 188 pj_file_close(fport->fd); 189 return status; 190 } 141 191 } 142 192 143 193 /* Set buffer size. */ … … 258 308 const pjmedia_frame *frame) 259 309 { 260 310 struct file_port *fport = (struct file_port *)this_port; 311 unsigned frame_size; 261 312 313 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) 314 frame_size = frame->size; 315 else 316 frame_size = frame->size >> 1; 317 262 318 /* Flush buffer if we don't have enough room for the frame. */ 263 if (fport->writepos + frame ->size > fport->buf + fport->bufsize) {319 if (fport->writepos + frame_size > fport->buf + fport->bufsize) { 264 320 pj_status_t status; 265 321 status = flush_buffer(fport); 266 322 if (status != PJ_SUCCESS) … … 268 324 } 269 325 270 326 /* Check if frame is not too large. */ 271 PJ_ASSERT_RETURN(fport->writepos+frame ->size <= fport->buf+fport->bufsize,327 PJ_ASSERT_RETURN(fport->writepos+frame_size <= fport->buf+fport->bufsize, 272 328 PJMEDIA_EFRMFILETOOBIG); 273 329 274 330 /* Copy frame to buffer. */ 275 pj_memcpy(fport->writepos, frame->buf, frame->size); 276 fport->writepos += frame->size; 331 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) { 332 pj_memcpy(fport->writepos, frame->buf, frame->size); 333 } else { 334 unsigned i; 335 pj_int16_t *src = (pj_int16_t*)frame->buf; 336 pj_uint8_t *dst = (pj_uint8_t*)fport->writepos; 277 337 338 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) { 339 for (i = 0; i < frame_size; ++i) { 340 *dst++ = pjmedia_linear2ulaw(*src++); 341 } 342 } else { 343 for (i = 0; i < frame_size; ++i) { 344 *dst++ = pjmedia_linear2alaw(*src++); 345 } 346 } 347 348 } 349 fport->writepos += frame_size; 350 278 351 /* Increment total written, and check if we need to call callback */ 279 fport->total += frame ->size;352 fport->total += frame_size; 280 353 if (fport->cb && fport->total >= fport->cb_size) { 281 354 pj_status_t (*cb)(pjmedia_port*, void*); 282 355 pj_status_t status; … … 314 387 pj_uint32_t wave_file_len; 315 388 pj_uint32_t wave_data_len; 316 389 pj_status_t status; 390 pj_uint32_t data_len_pos = DATA_LEN_POS; 317 391 318 392 /* Flush remaining buffers. */ 319 393 if (fport->writepos != fport->buf) … … 341 415 status = pj_file_write(fport->fd, &wave_file_len, &bytes); 342 416 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 343 417 418 /* Write samples_len in FACT chunk */ 419 if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) { 420 enum { SAMPLES_LEN_POS = 44 }; 421 pj_uint32_t wav_samples_len; 422 423 /* Adjust wave_data_len & data_len_pos since there is FACT chunk */ 424 wave_data_len -= 12; 425 data_len_pos += 12; 426 wav_samples_len = wave_data_len; 427 428 /* Seek to samples_len field. */ 429 status = pj_file_setpos(fport->fd, SAMPLES_LEN_POS, PJ_SEEK_SET); 430 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 431 432 /* Write samples_len */ 433 bytes = sizeof(wav_samples_len); 434 status = pj_file_write(fport->fd, &wav_samples_len, &bytes); 435 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 436 } 437 344 438 /* Seek to data_len field. */ 345 status = pj_file_setpos(fport->fd, DATA_LEN_POS, PJ_SEEK_SET);439 status = pj_file_setpos(fport->fd, data_len_pos, PJ_SEEK_SET); 346 440 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 347 441 348 442 /* Write file_len */ -
pjmedia/src/pjmedia/wav_player.c
17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 19 #include <pjmedia/wav_port.h> 20 #include <pjmedia/alaw_ulaw.h> 20 21 #include <pjmedia/errno.h> 21 22 #include <pjmedia/wave.h> 22 23 #include <pj/assert.h> … … 31 32 32 33 33 34 #define SIGNATURE PJMEDIA_PORT_SIGNATURE('F', 'P', 'l', 'y') 34 #define B YTES_PER_SAMPLE 235 #define BITS_PER_SAMPLE 16 35 36 36 37 37 #if 1 38 38 # define TRACE_(x) PJ_LOG(4,x) 39 39 #else … … 56 56 { 57 57 pjmedia_port base; 58 58 unsigned options; 59 pjmedia_wave_fmt_tag fmt_tag; 60 pj_uint16_t bytes_per_sample; 59 61 pj_bool_t eof; 60 62 pj_size_t bufsize; 61 63 char *buf; … … 145 147 } 146 148 147 149 /* Convert samples to host rep */ 148 samples_to_host((pj_int16_t*)fport->buf, fport->bufsize/BYTES_PER_SAMPLE); 150 samples_to_host((pj_int16_t*)fport->buf, 151 fport->bufsize/fport->bytes_per_sample); 149 152 150 153 return PJ_SUCCESS; 151 154 } … … 165 168 pj_ssize_t size_to_read, size_read; 166 169 struct file_reader_port *fport; 167 170 pj_off_t pos; 168 pj_status_t status ;171 pj_status_t status = PJ_SUCCESS; 169 172 170 173 171 174 /* Check arguments. */ … … 235 238 return PJMEDIA_ENOTVALIDWAVE; 236 239 } 237 240 238 /* Must be PCM with 16bits per sample */ 239 if (wave_hdr.fmt_hdr.fmt_tag != 1 || 240 wave_hdr.fmt_hdr.bits_per_sample != 16) 241 { 242 pj_file_close(fport->fd); 243 return PJMEDIA_EWAVEUNSUPP; 241 /* Validate format and its attributes (i.e: bits per sample, block align) */ 242 switch (wave_hdr.fmt_hdr.fmt_tag) { 243 case PJMEDIA_WAVE_FMT_TAG_PCM: 244 if (wave_hdr.fmt_hdr.bits_per_sample != 16 || 245 wave_hdr.fmt_hdr.block_align != 2) 246 status = PJMEDIA_EWAVEUNSUPP; 247 break; 248 249 case PJMEDIA_WAVE_FMT_TAG_ALAW: 250 case PJMEDIA_WAVE_FMT_TAG_ULAW: 251 if (wave_hdr.fmt_hdr.bits_per_sample != 8 || 252 wave_hdr.fmt_hdr.block_align != 1) 253 status = PJMEDIA_ENOTVALIDWAVE; 254 break; 255 256 default: 257 status = PJMEDIA_EWAVEUNSUPP; 258 break; 244 259 } 245 260 246 /* Block align must be 2*nchannels */ 247 if (wave_hdr.fmt_hdr.block_align != wave_hdr.fmt_hdr.nchan*BYTES_PER_SAMPLE) { 261 if (status != PJ_SUCCESS) { 248 262 pj_file_close(fport->fd); 249 return PJMEDIA_EWAVEUNSUPP;263 return status; 250 264 } 251 265 266 fport->fmt_tag = wave_hdr.fmt_hdr.fmt_tag; 267 fport->bytes_per_sample = wave_hdr.fmt_hdr.block_align; 268 252 269 /* If length of fmt_header is greater than 16, skip the remaining 253 270 * fmt header data. 254 271 */ … … 299 316 pj_file_close(fport->fd); 300 317 return PJMEDIA_EWAVEUNSUPP; 301 318 } 302 if (wave_hdr.data_hdr.len < 200) { 319 if (wave_hdr.data_hdr.len < ptime * wave_hdr.fmt_hdr.sample_rate * 320 wave_hdr.fmt_hdr.nchan / 1000) 321 { 303 322 pj_file_close(fport->fd); 304 323 return PJMEDIA_EWAVETOOSHORT; 305 324 } … … 312 331 /* Update port info. */ 313 332 fport->base.info.channel_count = wave_hdr.fmt_hdr.nchan; 314 333 fport->base.info.clock_rate = wave_hdr.fmt_hdr.sample_rate; 315 fport->base.info.bits_per_sample = wave_hdr.fmt_hdr.bits_per_sample;334 fport->base.info.bits_per_sample = BITS_PER_SAMPLE; 316 335 fport->base.info.samples_per_frame = fport->base.info.clock_rate * 317 336 wave_hdr.fmt_hdr.nchan * 318 337 ptime / 1000; … … 337 356 /* samples_per_frame must be smaller than bufsize (because get_frame() 338 357 * doesn't handle this case). 339 358 */ 340 if (fport->base.info.samples_per_frame * BYTES_PER_SAMPLE>=359 if (fport->base.info.samples_per_frame * fport->bytes_per_sample >= 341 360 fport->bufsize) 342 361 { 343 362 pj_file_close(fport->fd); … … 523 542 fport->eof = PJ_FALSE; 524 543 } 525 544 526 //frame_size = fport->base.info.bytes_per_frame; 527 //pj_assert(frame->size == frame_size); 528 frame_size = frame->size; 545 //pj_assert(frame->size == fport->base.info.bytes_per_frame); 546 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) { 547 frame_size = frame->size; 548 //frame->size = frame_size; 549 } else { 550 /* Must be ULAW or ALAW */ 551 pj_assert(fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW || 552 fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW); 529 553 554 frame_size = frame->size >> 1; 555 frame->size = frame_size << 1; 556 } 557 530 558 /* Copy frame from buffer. */ 531 559 frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 532 frame->size = frame_size;533 560 frame->timestamp.u64 = 0; 534 561 535 562 if ((fport->readpos + frame_size) <= (fport->buf + fport->bufsize)) … … 579 606 fport->readpos = fport->buf + (frame_size - endread); 580 607 } 581 608 609 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW || 610 fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW) 611 { 612 unsigned i; 613 pj_uint16_t *dst; 614 pj_uint8_t *src; 615 616 dst = (pj_uint16_t*)frame->buf + frame_size - 1; 617 src = (pj_uint8_t*)frame->buf + frame_size - 1; 618 619 if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) { 620 for (i = 0; i < frame_size; ++i) { 621 *dst-- = (pj_uint16_t) pjmedia_ulaw2linear(*src--); 622 } 623 } else { 624 for (i = 0; i < frame_size; ++i) { 625 *dst-- = (pj_uint16_t) pjmedia_alaw2linear(*src--); 626 } 627 } 628 } 629 582 630 return PJ_SUCCESS; 583 631 } 584 632