RTS API Documentation  1.10.11
switch_core_file.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Michael Jerris <mike@jerris.com>
28  * Paul D. Tinsley <pdt at jackhammer.org>
29  * John Wehle <john@feith.com>
30  *
31  *
32  * switch_core_file.c -- Main Core Library (File I/O Functions)
33  *
34  */
35 
36 #include <switch.h>
38 
39 
40 static switch_status_t get_file_size(switch_file_handle_t *fh, const char **string)
41 {
42  switch_status_t status;
43  switch_file_t *newfile;
44  switch_size_t size = 0;
45 
46  switch_assert(string);
47 
49 
50  if (status != SWITCH_STATUS_SUCCESS) {
51  return status;
52  }
53 
54  size = switch_file_get_size(newfile);
55 
56  if (size) {
57  *string = switch_core_sprintf(fh->memory_pool, "%" SWITCH_SIZE_T_FMT, size);
58  }
59 
60  status = switch_file_close(newfile);
61 
62  return status;
63 }
64 
65 SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, const char *func, int line,
67  const char *file_path,
68  uint32_t channels, uint32_t rate, unsigned int flags, switch_memory_pool_t *pool)
69 {
70  char *ext;
72  char stream_name[128] = "";
73  char *rhs = NULL;
74  const char *spool_path = NULL;
75  int is_stream = 0;
76  char *fp = NULL;
77  int to = 0;
78  int force_channels = 0;
79  uint32_t core_channel_limit;
80 
82  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Handle already open\n");
83  return SWITCH_STATUS_FALSE;
84  }
85 
86  fh->samples_in = 0;
87 
88  if (!(flags & SWITCH_FILE_FLAG_WRITE)) {
89  fh->samplerate = 0;
90  fh->native_rate = 0;
91  fh->channels = 0;
92  fh->real_channels = 0;
93  }
94 
95  if (!fh->samplerate) {
96  if (!(fh->samplerate = rate)) {
97  fh->samplerate = 8000;
98  }
99  }
100 
101  if (zstr(file_path)) {
102  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Filename\n");
103  return SWITCH_STATUS_FALSE;
104  }
105 
106  fh->flags = flags;
107 
108  if (pool) {
109  fh->memory_pool = pool;
110  } else {
113  return status;
114  }
116  }
117 
119 
120  fh->mm.samplerate = 44100;
121  fh->mm.channels = 1;
122  fh->mm.keyint = 60;
123  fh->mm.ab = 128;
126  fh->mm.try_hardware_encoder = 1;
127 
128  if (*file_path == '{') {
129  char *timeout;
130  char *modname;
131  const char *val;
132  int tmp;
133 
134  fp = switch_core_strdup(fh->memory_pool, file_path);
135 
136  while (*fp == '{') {
137  char *parsed = NULL;
138 
139  if (switch_event_create_brackets(fp, '{', '}', ',', &fh->params, &parsed, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS || !parsed) {
141  goto fail;
142  }
143 
144  fp = parsed;
145  }
146 
147  file_path = fp;
148 
149  if ((timeout = switch_event_get_header(fh->params, "timeout"))) {
150  if ((to = atoi(timeout)) < 1) {
151  to = 0;
152  }
153  }
154 
155  if ((modname = switch_event_get_header(fh->params, "modname"))) {
156  fh->modname = switch_core_strdup(fh->memory_pool, modname);
157  }
158 
159  if ((val = switch_event_get_header(fh->params, "samplerate"))) {
160  tmp = atoi(val);
161  if (tmp >= 8000) {
162  fh->mm.samplerate = tmp;
163  }
164  }
165 
166  if ((val = switch_event_get_header(fh->params, "force_channels"))) {
167  tmp = atoi(val);
168  if (tmp >= 0 && tmp < 3) {
169  force_channels = tmp;
170  }
171  }
172 
173  if ((val = switch_event_get_header(fh->params, "ab"))) {
174  tmp = atoi(val);
175  if (tmp > 16) {
176  fh->mm.ab = tmp;
177  }
178  }
179 
180  if ((val = switch_event_get_header(fh->params, "cbr"))) {
181  tmp = switch_true(val);
182  fh->mm.cbr = tmp;
183  }
184 
185  if ((val = switch_event_get_header(fh->params, "vb"))) {
186  tmp = atoi(val);
187 
188  if (strrchr(val, 'k')) {
189  tmp *= 1024;
190  } else if (strrchr(val, 'm')) {
191  tmp *= 1048576;
192  }
193 
194  fh->mm.vb = tmp;
195  }
196 
197  if ((val = switch_event_get_header(fh->params, "vw"))) {
198  tmp = atoi(val);
199  if (tmp > 0) {
200  fh->mm.vw = tmp;
201  }
202  }
203 
204  if ((val = switch_event_get_header(fh->params, "vh"))) {
205  tmp = atoi(val);
206  if (tmp > 0) {
207  fh->mm.vh = tmp;
208  }
209  }
210 
211  if ((val = switch_event_get_header(fh->params, "try_hardware_encoder"))) {
213  }
214 
215  if ((val = switch_event_get_header(fh->params, "auth_username"))) {
217  }
218 
219  if ((val = switch_event_get_header(fh->params, "auth_password"))) {
221  }
222 
223  if ((val = switch_event_get_header(fh->params, "fps"))) {
224  float ftmp = atof(val);
225  if (ftmp > 0.0f) {
226  fh->mm.fps = ftmp;
227  }
228  }
229 
230  if ((val = switch_event_get_header(fh->params, "vbuf"))) {
231  tmp = atoi(val);
232 
233  if (strrchr(val, 'k')) {
234  tmp *= 1024;
235  } else if (strrchr(val, 'm')) {
236  tmp *= 1048576;
237  }
238 
239  if (tmp > 0 && tmp < 104857600 /*100mb*/) {
240  fh->mm.vbuf = tmp;
241  } else {
242  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid buffer size: %d\n", tmp);
243  }
244  }
245 
246  if ((val = switch_event_get_header(fh->params, "vencspd"))) {
247  if (!strcasecmp(val, "slow")) {
249  } else if (!strcasecmp(val, "medium")) {
251  } else if (!strcasecmp(val, "fast")) {
253  } else {
254  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid video encode speed: %s\n", val);
255  }
256  }
257 
258  if ((val = switch_event_get_header(fh->params, "vprofile"))) {
259  if (!strcasecmp(val, "baseline")) {
261  } else if (!strcasecmp(val, "main")) {
263  } else if (!strcasecmp(val, "high")) {
265  } else {
266  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid video profile: %s\n", val);
267  }
268  }
269  }
270 
272  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] is a directory not a file.\n", file_path);
273  status = SWITCH_STATUS_GENERR;
274  goto fail;
275  }
276 
277  if (!strncasecmp(file_path, "https://", 8) && (switch_stristr("youtube", file_path) || switch_stristr("youtu.be", file_path))) {
278  char *youtube_root = NULL;
279 
280  if ((youtube_root = switch_core_get_variable_pdup("youtube_resolver", fh->memory_pool))) {
281  char *resolve_url, *encoded, *url_buf;
282  switch_size_t url_buflen = 0;
283  switch_stream_handle_t stream = { 0 };
284  const char *video = NULL, *format = "best";
285 
286  url_buflen = strlen(file_path) * 4;
287  url_buf = switch_core_alloc(fh->memory_pool, url_buflen);
288  encoded = switch_url_encode(file_path, url_buf, url_buflen);
289 
290  if (fh->params && (video = switch_event_get_header(fh->params, "video")) && switch_false(video)) {
291  format = "bestaudio";
292  }
293 
294  resolve_url = switch_core_sprintf(fh->memory_pool, "%s?url=%s&format=%s", youtube_root, encoded, format);
295 
296  SWITCH_STANDARD_STREAM(stream);
297 
298  //Depends on mod_curl *shrug*
299  switch_api_execute("curl", resolve_url, NULL, &stream);
300 
301  if (stream.data && !strncasecmp("https://", (char *)stream.data, 8)) {
302  char *url = (char *) stream.data;
303  while (end_of_p(url) > url && (end_of(url) == '\n' || end_of(url) == '\r')) {
304  end_of(url) = '\0';
305  }
306  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "resolved url to: %s\n", url);
307  file_path = switch_core_sprintf(fh->memory_pool, "av://%s", url);
308  } else {
309  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "YOUTUBE RESOLVER FAIL: %s\n", (char *) stream.data);
310  }
311 
312  switch_safe_free(stream.data);
313  }
314  }
315 
316  if ((rhs = strstr(file_path, SWITCH_URL_SEPARATOR))) {
317  switch_copy_string(stream_name, file_path, (rhs + 1) - file_path);
318  ext = stream_name;
319  file_path = rhs + 3;
320  fh->stream_name = switch_core_strdup(fh->memory_pool, stream_name);
321  fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
322  is_stream = 1;
323  } else {
324  if ((flags & SWITCH_FILE_FLAG_WRITE)) {
325 
326  if (fh->params) {
327  spool_path = switch_event_get_header(fh->params, "spool_path");
328  }
329 
330  if (!spool_path) {
332  }
333  }
334 
335  if ((ext = strrchr(file_path, '.')) == 0) {
336  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown file Format [%s]\n", file_path);
338  }
339  ext++;
340  fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
341  }
342 
343 
344 
346  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid file format [%s] for [%s]!\n", ext, file_path);
348  }
349 
350  fh->file = file;
351  fh->func = func;
352  fh->line = line;
353 
356  }
357 
358  if (spool_path) {
359  char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
360  switch_uuid_t uuid;
361  switch_uuid_get(&uuid);
362  switch_uuid_format(uuid_str, &uuid);
363 
364  fh->spool_path = switch_core_sprintf(fh->memory_pool, "%s%s%s.%s", spool_path, SWITCH_PATH_SEPARATOR, uuid_str, ext);
365  } else {
366  fh->spool_path = NULL;
367  }
368 
369  if (rhs) {
370  fh->handler = switch_core_strdup(fh->memory_pool, rhs);
371  } else {
372  fh->handler = NULL;
373  }
374 
375  if (force_channels == channels) {
376  force_channels = 0;
377  }
378 
379  if (force_channels && force_channels > 0 && force_channels < 3) {
380  fh->real_channels = channels ? channels : fh->channels;
381  fh->channels = force_channels;
382  fh->mm.channels = fh->channels;
383  } else {
384 
385  if (channels) {
386  fh->channels = channels;
387  } else {
388  fh->channels = 1;
389  }
390 
391  fh->mm.channels = fh->channels;
392  }
393 
394  file_path = fh->spool_path ? fh->spool_path : fh->file_path;
395 
396  if ((status = fh->file_interface->file_open(fh, file_path)) != SWITCH_STATUS_SUCCESS) {
397  if (fh->spool_path) {
398  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Spool dir is set. Make sure [%s] is also a valid path\n", fh->spool_path);
399  }
401  goto fail;
402  }
403 
404  if (fh->channels > 2) {
405  /* just show a warning for more than 2 channels, no matter if we allow them or not */
406  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File [%s] has more than 2 channels: [%u]\n", file_path, fh->channels);
407  }
408 
409  core_channel_limit = switch_core_max_audio_channels(0);
410  if (core_channel_limit && fh->channels > core_channel_limit) {
411  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File [%s] has more channels (%u) than limit (%u). Closing.\n", file_path, fh->channels, core_channel_limit);
412  fh->file_interface->file_close(fh);
415  }
416 
417  if (!force_channels && !fh->real_channels) {
418  fh->real_channels = fh->channels;
419 
420  if (channels) {
421  fh->channels = channels;
422  }
423  }
424 
425  if ((flags & SWITCH_FILE_FLAG_WRITE) && !is_stream && (status = switch_file_exists(file_path, fh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
426  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] not created!\n", file_path);
427  fh->file_interface->file_close(fh);
429  goto fail;
430  }
431 
432  if (to) {
433  fh->max_samples = (fh->samplerate / 1000) * to;
434  }
435 
436 
437  if ((flags & SWITCH_FILE_FLAG_READ)) {
438  fh->native_rate = fh->samplerate;
439  } else {
440  fh->native_rate = rate;
441  }
442 
443  if (fh->samplerate && rate && fh->samplerate != rate) {
444  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "File %s sample rate %d doesn't match requested rate %d\n", file_path, fh->samplerate, rate);
445  if ((flags & SWITCH_FILE_FLAG_READ)) {
446  fh->samplerate = rate;
447  }
448  }
449 
451  fh->pre_buffer_datalen = 0;
452  }
453 
454  if (fh->pre_buffer_datalen) {
455  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Prebuffering %d bytes\n", (int)fh->pre_buffer_datalen);
458  }
459 
460 
461  if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) {
462  fh->cur_channels = fh->real_channels;
463  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to %d channel%s will occur.\n", fh->real_channels, fh->channels, fh->channels == 1 ? "" : "s");
464  }
465 
467  return status;
468 
469  fail:
470 
472 
473  if (fh->params) {
475  }
476 
477  fh->samples_in = 0;
478  fh->max_samples = 0;
479 
482  }
483 
484  return status;
485 }
486 
488 {
490  switch_size_t want, orig_len = *len;
491 
492  switch_assert(fh != NULL);
493  switch_assert(fh->file_interface != NULL);
494 
496  return SWITCH_STATUS_FALSE;
497  }
498 
499  top:
500 
501  if (fh->max_samples > 0 && fh->samples_in >= (switch_size_t)fh->max_samples) {
502  *len = 0;
503  return SWITCH_STATUS_FALSE;
504  }
505 
506  if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2 * fh->channels) {
507  *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
508  return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
509  }
510 
514  *len = 0;
515  return SWITCH_STATUS_FALSE;
516  }
517 
518  want = *len;
519 
520  more:
521 
522  if (fh->pre_buffer) {
523  switch_size_t rlen;
524  int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);
525 
527  rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2 / fh->real_channels;
528 
529  if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2 * fh->channels) {
530  if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) {
531  return SWITCH_STATUS_BREAK;
532  }
533 
534 
535  if (status != SWITCH_STATUS_SUCCESS || !rlen) {
537  } else {
538  if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
539  switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->real_channels, fh->channels);
540  }
541  switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2 * fh->channels);
542  }
543  }
544  }
545 
546  rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2 * fh->channels);
547  fh->samples_in += rlen;
548  *len = asis ? rlen : rlen / 2 / fh->channels;
549 
550  if (*len == 0) {
552  goto top;
553  } else {
554  status = SWITCH_STATUS_SUCCESS;
555  }
556 
557  } else {
558 
559  if ((status = fh->file_interface->file_read(fh, data, len)) == SWITCH_STATUS_BREAK) {
560  return SWITCH_STATUS_BREAK;
561  }
562 
563  if (status != SWITCH_STATUS_SUCCESS || !*len) {
565  goto top;
566  }
567 
568  fh->samples_in += *len;
569 
570  if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
571  switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels);
572  }
573  }
574 
575  if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) {
576  if (!fh->resampler) {
578  fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) {
579  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
580  return SWITCH_STATUS_GENERR;
581  }
582  }
583 
584  switch_resample_process(fh->resampler, data, (uint32_t) *len);
585 
586  if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) {
587  if (!fh->buffer) {
588  int factor = fh->resampler->to_len * fh->samplerate / 1000;
589  switch_buffer_create_dynamic(&fh->buffer, factor, factor, 0);
590  switch_assert(fh->buffer);
591  }
592  if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2 * fh->channels) {
593  void *mem;
594  fh->dbuflen = fh->resampler->to_len * 2 * fh->channels;
595  mem = realloc(fh->dbuf, fh->dbuflen);
596  switch_assert(mem);
597  fh->dbuf = mem;
598  }
599  switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen);
600  memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
601  switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2 * fh->channels);
602 
603  if (switch_buffer_inuse(fh->buffer) < want * 2 * fh->channels) {
604  *len = want;
605  goto more;
606  }
607  *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
608  } else {
609  memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
610  *len = fh->resampler->to_len;
611  }
612 
613 
614  }
615 
616  return status;
617 }
618 
620 {
622 }
623 
625 {
626  switch_size_t orig_len = *len;
627 
628  switch_assert(fh != NULL);
629  switch_assert(fh->file_interface != NULL);
630 
632  return SWITCH_STATUS_FALSE;
633  }
634 
635  if (!fh->file_interface->file_write) {
636  return SWITCH_STATUS_FALSE;
637  }
638 
640  return SWITCH_STATUS_SUCCESS;
641  }
642 
643 
644  if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
645  int need = *len * 2 * (fh->real_channels > fh->channels ? fh->real_channels : fh->channels);
646 
647  if (need > fh->muxlen) {
648  fh->muxbuf = realloc(fh->muxbuf, need);
649  switch_assert(fh->muxbuf);
650  fh->muxlen = need;
651  }
652 
653  if (fh->muxbuf) {
654  memcpy(fh->muxbuf, data, *len * 2);
655  data = fh->muxbuf;
656  }
657 
658  switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels);
659  }
660 
661 
662  if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) {
663  if (!fh->resampler) {
665  fh->native_rate,
666  fh->samplerate,
667  (uint32_t) orig_len * 2 * fh->channels, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) {
668  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
669  return SWITCH_STATUS_GENERR;
670  }
671  }
672 
673  switch_resample_process(fh->resampler, data, (uint32_t) * len);
674 
675  if (fh->resampler->to_len > orig_len) {
676  if (!fh->dbuf || (fh->dbuflen < fh->resampler->to_len * 2 * fh->channels)) {
677  void *mem;
678  fh->dbuflen = fh->resampler->to_len * 2 * fh->channels;
679  mem = realloc(fh->dbuf, fh->dbuflen);
680  switch_assert(mem);
681  fh->dbuf = mem;
682  }
683  switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen);
684  memcpy(fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
685  data = fh->dbuf;
686  } else {
687  memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
688  }
689 
690  *len = fh->resampler->to_len;
691  }
692 
693  if (!*len) {
694  return SWITCH_STATUS_SUCCESS;
695  }
696 
697 
698  if (fh->pre_buffer) {
699  switch_size_t rlen, blen;
700  switch_size_t datalen_adj = fh->pre_buffer_datalen;
702  int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);
703 
704  switch_buffer_write(fh->pre_buffer, data, (asis ? *len : *len * 2) * fh->channels);
705 
706  rlen = switch_buffer_inuse(fh->pre_buffer);
707 
708  if (fh->pre_buffer_datalen % fh->channels) {
709  datalen_adj = fh->pre_buffer_datalen - (fh->pre_buffer_datalen % fh->channels);
710  }
711 
712  if (rlen >= datalen_adj) {
713  if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, datalen_adj))) {
714  if (!asis)
715  blen /= 2;
716  if (fh->channels > 1)
717  blen /= fh->channels;
718  if ((status = fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen)) != SWITCH_STATUS_SUCCESS) {
719  *len = 0;
720  }
721  }
722  }
723  fh->samples_out += orig_len;
724  return status;
725  } else {
726  switch_status_t status;
727  if ((status = fh->file_interface->file_write(fh, data, len)) == SWITCH_STATUS_SUCCESS) {
728  fh->samples_out += orig_len;
729  }
730  return status;
731  }
732 }
733 
735 {
736  switch_assert(fh != NULL);
737  switch_assert(fh->file_interface != NULL);
738 
740  return SWITCH_STATUS_GENERR;
741  }
742 
743  if (!fh->file_interface->file_write_video) {
744  return SWITCH_STATUS_FALSE;
745  }
746 
748  return SWITCH_STATUS_SUCCESS;
749  }
750 
751  return fh->file_interface->file_write_video(fh, frame);
752 
753 }
754 
756 {
757  switch_status_t status;
758 
759  switch_assert(fh != NULL);
760  switch_assert(fh->file_interface != NULL);
761 
763  return SWITCH_STATUS_GENERR;
764  }
765 
766  if (!fh->file_interface->file_read_video) {
767  return SWITCH_STATUS_FALSE;
768  }
769 
770  status = fh->file_interface->file_read_video(fh, frame, flags);
771 
772  if (status == SWITCH_STATUS_FALSE) {
774  }
775 
776  return status;
777 }
778 
779 SWITCH_DECLARE(switch_status_t) switch_core_file_seek(switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples, int whence)
780 {
781  switch_status_t status;
782  int ok = 1;
783 
784  switch_assert(fh != NULL);
785 
787  ok = 0;
788  } else if (switch_test_flag(fh, SWITCH_FILE_FLAG_WRITE)) {
790  ok = 0;
791  }
792  } else if (!switch_test_flag(fh, SWITCH_FILE_FLAG_READ)) {
793  ok = 0;
794  }
795 
796  if (!ok) {
797  return SWITCH_STATUS_FALSE;
798  }
799 
800  if (fh->buffer) {
802  }
803 
804  if (fh->pre_buffer) {
806  }
807 
808  if (whence == SWITCH_SEEK_CUR) {
809  unsigned int cur = 0;
810 
812  fh->file_interface->file_seek(fh, &cur, fh->samples_out, SEEK_SET);
813  } else {
814  fh->file_interface->file_seek(fh, &cur, fh->offset_pos, SEEK_SET);
815  }
816  }
817 
819  status = fh->file_interface->file_seek(fh, cur_pos, samples, whence);
820 
821  fh->offset_pos = *cur_pos;
822 
824  fh->samples_out = *cur_pos;
825  }
826 
827  return status;
828 }
829 
831 {
832  switch_assert(fh != NULL);
833  switch_assert(fh->file_interface != NULL);
834 
836  return SWITCH_STATUS_FALSE;
837  }
838 
839  if (!fh->file_interface->file_set_string) {
840  return SWITCH_STATUS_FALSE;
841  }
842 
843  return fh->file_interface->file_set_string(fh, col, string);
844 }
845 
847 {
848  switch_status_t status;
849 
850  switch_assert(fh != NULL);
851  switch_assert(fh->file_interface != NULL);
852 
854  return SWITCH_STATUS_FALSE;
855  }
856 
857  if (!fh->file_interface->file_get_string) {
858  if (col == SWITCH_AUDIO_COL_STR_FILE_SIZE) {
859  return get_file_size(fh, string);
860  }
861 
862  return SWITCH_STATUS_FALSE;
863  }
864 
865  status = fh->file_interface->file_get_string(fh, col, string);
866 
867  if (status == SWITCH_STATUS_SUCCESS && string) return status;
868 
869  if (col == SWITCH_AUDIO_COL_STR_FILE_SIZE) {
870  return get_file_size(fh, string);
871  }
872 
873  return status;
874 }
875 
877 {
878  switch_status_t status;
879 
880  switch_assert(fh != NULL);
881  switch_assert(fh->file_interface != NULL);
882 
884  return SWITCH_STATUS_FALSE;
885  }
886 
887  if (!fh->file_interface->file_truncate) {
888  return SWITCH_STATUS_FALSE;
889  }
890 
891  if ((status = fh->file_interface->file_truncate(fh, offset)) == SWITCH_STATUS_SUCCESS) {
892  if (fh->buffer) {
894  }
895  if (fh->pre_buffer) {
897  }
898  fh->samples_out = 0;
899  fh->pos = 0;
900  }
901 
902  return status;
903 
904 }
905 
907 {
909 
910  switch_assert(fh != NULL);
911  switch_assert(fh->file_interface != NULL);
912 
914  return SWITCH_STATUS_FALSE;
915  }
916 
917  switch(command) {
918  case SCFC_FLUSH_AUDIO:
919  if (fh->pre_buffer) {
921  }
922  break;
923  default:
924  break;
925  }
926 
927  if (fh->file_interface->file_command) {
929  status = fh->file_interface->file_command(fh, command);
931  }
932 
933  return status;
934 }
935 
937 {
939 
940  switch_assert(fh != NULL);
941 
942  if (!fh->file_interface) {
943  return SWITCH_STATUS_FALSE;
944  }
945 
947  return SWITCH_STATUS_SUCCESS;
948  }
949 
950  if (fh->pre_buffer) {
952  switch_size_t blen;
953  int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);
954 
955  while (switch_buffer_inuse(fh->pre_buffer)) {
956  if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, fh->pre_buffer_datalen))) {
957  if (!asis)
958  blen /= 2;
959  if (fh->channels > 1)
960  blen /= fh->channels;
961 
962  if (fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen) != SWITCH_STATUS_SUCCESS) {
963  break;
964  }
965  }
966  }
967  }
968 
970  }
971 
974 
975  if (fh->file_interface->file_pre_close) {
976  status = fh->file_interface->file_pre_close(fh);
977  }
978 
979  return status;
980 }
981 
983 {
984  switch_status_t status;
986  uint8_t destroy_pool = 0;
987 
988  switch_assert(oldfh != NULL);
989  switch_assert(newfh != NULL);
990 
991  if (!pool) {
992  if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
993  return status;
994  }
995 
996  destroy_pool = 1;
997  }
998 
999  if (!(fh = switch_core_alloc(pool, sizeof(switch_file_handle_t)))) {
1001  }
1002 
1003  memcpy(fh, oldfh, sizeof(switch_file_handle_t));
1004 
1005  if (!destroy_pool) {
1007  } else {
1008  fh->memory_pool = pool;
1010  }
1011 
1012  if ((status = switch_mutex_init(&fh->flag_mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
1013  switch_goto_status(status, err);
1014  }
1015 
1016 #define DUP_CHECK(dup) if (oldfh->dup && !(fh->dup = switch_core_strdup(pool, oldfh->dup))) {switch_goto_status(SWITCH_STATUS_MEMERR, err);}
1017 
1018  DUP_CHECK(prefix);
1019  DUP_CHECK(modname);
1020  DUP_CHECK(mm.auth_username);
1021  DUP_CHECK(mm.auth_password);
1022  DUP_CHECK(stream_name);
1023  DUP_CHECK(file_path);
1024  DUP_CHECK(handler);
1025  DUP_CHECK(spool_path);
1026 
1027  fh->pre_buffer_data = NULL;
1028  if (oldfh->pre_buffer_data) {
1029  switch_size_t pre_buffer_data_size = oldfh->pre_buffer_datalen * oldfh->channels;
1030  if (pre_buffer_data_size) {
1031  if (!(fh->pre_buffer_data = switch_core_alloc(pool, pre_buffer_data_size))) {
1033  }
1034 
1035  memcpy(fh->pre_buffer_data, oldfh->pre_buffer_data, pre_buffer_data_size);
1036  }
1037  }
1038 
1039  *newfh = fh;
1040 
1041  return SWITCH_STATUS_SUCCESS;
1042 
1043 err:
1044  if (destroy_pool) {
1046  }
1047 
1048  return status;
1049 }
1050 
1052 {
1054 
1056  status = switch_core_file_pre_close(fh);
1057  } else if (!switch_test_flag(fh, SWITCH_FILE_PRE_CLOSED)) {
1058  return SWITCH_STATUS_FALSE;
1059  }
1060 
1062 
1063  fh->file_interface->file_close(fh);
1064 
1065  if (fh->params) {
1067  }
1068 
1069  fh->samples_in = 0;
1070  fh->max_samples = 0;
1071 
1072  if (fh->buffer) {
1074  }
1075 
1077 
1080  }
1081 
1082  fh->memory_pool = NULL;
1083 
1084  switch_safe_free(fh->dbuf);
1085  switch_safe_free(fh->muxbuf);
1086 
1087  if (fh->spool_path) {
1088  char *command;
1089 
1090 #ifdef _MSC_VER
1091  command = switch_mprintf("move %s %s", fh->spool_path, fh->file_path);
1092 #else
1093  command = switch_mprintf("/bin/mv %s %s", fh->spool_path, fh->file_path);
1094 #endif
1095  if (system(command) == -1) {
1096  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to copy spooled file [%s] to [%s] because of a command error : %s\n", fh->spool_path, fh->file_path, command);
1097  } else {
1098  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Copy spooled file [%s] to [%s]\n", fh->spool_path, fh->file_path);
1099  }
1100  free(command);
1101  }
1102 
1104  fh->file_interface = NULL;
1105 
1106  return status;
1107 }
1108 
1109 /* For Emacs:
1110  * Local Variables:
1111  * mode:c
1112  * indent-tabs-mode:t
1113  * tab-width:4
1114  * c-basic-offset:4
1115  * End:
1116  * For VIM:
1117  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1118  */
switch_status_t switch_core_file_set_string(switch_file_handle_t *fh, switch_audio_col_t col, const char *string)
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core&#39;s master pool.
Definition: switch_core.h:633
switch_status_t switch_directory_exists(const char *dirname, switch_memory_pool_t *pool)
Definition: switch_apr.c:497
static switch_bool_t switch_true(const char *expr)
Evaluate the truthfullness of a string expression.
Definition: switch_utils.h:519
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
Definition: switch_utils.h:700
#define SWITCH_CHANNEL_LOG
switch_size_t switch_buffer_read(_In_ switch_buffer_t *buffer, _In_ void *data, _In_ switch_size_t datalen)
Read data from a switch_buffer_t up to the ammount of datalen if it is available. Remove read data fr...
switch_status_t(* file_write)(switch_file_handle_t *, void *data, switch_size_t *len)
switch_status_t(* file_write_video)(switch_file_handle_t *, switch_frame_t *frame)
switch_status_t(* file_truncate)(switch_file_handle_t *, int64_t offset)
switch_status_t switch_buffer_create_dynamic(_Out_ switch_buffer_t **buffer, _In_ switch_size_t blocksize, _In_ switch_size_t start_len, _In_ switch_size_t max_len)
Allocate a new dynamic switch_buffer.
switch_file_interface_t * file_interface
#define SWITCH_FOPEN_READ
Definition: switch_apr.h:769
switch_status_t switch_core_file_read_video(switch_file_handle_t *fh, switch_frame_t *frame, switch_video_read_flag_t flags)
char * switch_core_get_variable_pdup(_In_z_ const char *varname, switch_memory_pool_t *pool)
cJSON *const to
switch_bool_t
Definition: switch_types.h:437
switch_status_t switch_event_create_brackets(char *data, char a, char b, char c, switch_event_t **event, char **new_data, switch_bool_t dup)
switch_audio_col_t
Definition: switch_types.h:613
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:733
#define SWITCH_URL_SEPARATOR
Definition: switch_types.h:126
switch_status_t switch_core_file_command(switch_file_handle_t *fh, switch_file_command_t command)
switch_status_t switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream)
Execute a registered API command.
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:642
switch_memory_pool_t * pool
switch_status_t(* file_read)(switch_file_handle_t *, void *data, switch_size_t *len)
#define fail()
Definition: tone2wav.c:70
#define SWITCH_AUDIO_SPOOL_PATH_VARIABLE
Definition: switch_types.h:128
uint8_t try_hardware_encoder
#define SWITCH_FPROT_OS_DEFAULT
Definition: switch_apr.h:726
#define SWITCH_RESAMPLE_QUALITY
#define end_of(_s)
Definition: switch_utils.h:685
char const int const cJSON_bool format
Definition: switch_cJSON.h:153
char * switch_url_encode(const char *url, char *buf, size_t len)
pack cur
switch_status_t(* file_read_video)(switch_file_handle_t *, switch_frame_t *frame, switch_video_read_flag_t flags)
void switch_resample_destroy(switch_audio_resampler_t **resampler)
Destroy an existing resampler handle.
switch_video_profile_t vprofile
char * auth_password
switch_size_t switch_buffer_write(_In_ switch_buffer_t *buffer, _In_bytecount_(datalen) const void *data, _In_ switch_size_t datalen)
Write data into a switch_buffer_t up to the length of datalen.
switch_status_t switch_core_file_handle_dup(switch_file_handle_t *oldfh, switch_file_handle_t **newfh, switch_memory_pool_t *pool)
Duplicates a file handle using another pool.
switch_audio_resampler_t * resampler
switch_memory_pool_t * memory_pool
#define end_of_p(_s)
Definition: switch_utils.h:686
#define zstr(x)
Definition: switch_utils.h:314
switch_video_read_flag_t
switch_status_t(* file_command)(switch_file_handle_t *fh, switch_file_command_t command)
switch_status_t(* file_get_string)(switch_file_handle_t *fh, switch_audio_col_t col, const char **string)
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:313
switch_status_t switch_core_file_seek(switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples, int whence)
#define UNPROTECT_INTERFACE(_it)
#define switch_clear_flag(obj, flag)
Clear a flag on an arbitrary object while locked.
Definition: switch_utils.h:724
switch_status_t(* file_seek)(switch_file_handle_t *, unsigned int *cur_pos, int64_t samples, int whence)
#define SWITCH_MUTEX_NESTED
Definition: switch_apr.h:318
#define SWITCH_PATH_SEPARATOR
Definition: switch_types.h:124
char * auth_username
switch_status_t switch_mutex_lock(switch_mutex_t *lock)
Definition: switch_apr.c:308
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:684
switch_file_interface_t * switch_loadable_module_get_file_interface(const char *name, const char *modname)
Retrieve the file format interface by it&#39;s registered name.
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:885
switch_buffer_t * pre_buffer
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:293
void switch_buffer_zero(_In_ switch_buffer_t *buffer)
Remove all data from the buffer.
uint32_t switch_core_max_audio_channels(uint32_t limit)
Definition: switch_core.c:2642
An abstraction of a data frame.
Definition: switch_frame.h:54
uintptr_t switch_size_t
#define switch_set_flag_locked(obj, flag)
Set a flag on an arbitrary object while locked.
Definition: switch_utils.h:707
switch_status_t(* file_set_string)(switch_file_handle_t *fh, switch_audio_col_t col, const char *string)
void switch_cond_next(void)
Definition: switch_time.c:658
#define SWITCH_STANDARD_STREAM(s)
char * switch_copy_string(_Out_z_cap_(dst_size) char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size)
switch_status_t(* file_close)(switch_file_handle_t *)
switch_video_encode_speed_t vencspd
void switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels)
switch_status_t switch_file_exists(const char *filename, switch_memory_pool_t *pool)
Definition: switch_apr.c:519
void switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
Definition: switch_apr.c:1140
switch_status_t switch_core_file_close(switch_file_handle_t *fh)
#define switch_clear_flag_locked(obj, flag)
Clear a flag on an arbitrary object.
Definition: switch_utils.h:717
#define SWITCH_SIZE_T_FMT
switch_status_t
Common return values.
switch_status_t(* file_pre_close)(switch_file_handle_t *fh)
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:287
switch_file_command_t
Main Library Header.
#define SWITCH_DECLARE(type)
void switch_uuid_get(switch_uuid_t *uuid)
Definition: switch_apr.c:1152
switch_status_t switch_core_file_get_string(switch_file_handle_t *fh, switch_audio_col_t col, const char **string)
switch_status_t switch_core_perform_file_open(const char *file, const char *func, int line, switch_file_handle_t *fh, const char *file_path, uint32_t channels, uint32_t rate, unsigned int flags, switch_memory_pool_t *pool)
#define switch_event_get_header(_e, _h)
Definition: switch_event.h:172
struct fspr_file_t switch_file_t
Definition: switch_apr.h:685
switch_status_t switch_core_file_truncate(switch_file_handle_t *fh, int64_t offset)
switch_bool_t switch_core_file_has_video(switch_file_handle_t *fh, switch_bool_t check_open)
switch_status_t switch_core_file_write_video(switch_file_handle_t *fh, switch_frame_t *frame)
switch_status_t switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len)
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:693
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
switch_status_t switch_core_file_pre_close(switch_file_handle_t *fh)
static int switch_false(const char *expr)
Evaluate the falsefullness of a string expression.
Definition: switch_utils.h:551
switch_status_t switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len)
while(unpack->bits_cur<=SWITCH_BITS_PER_BYTE)
struct fspr_pool_t switch_memory_pool_t
switch_status_t(* file_open)(switch_file_handle_t *, const char *file_path)
switch_status_t switch_file_open(switch_file_t **newf, const char *fname, int32_t flag, switch_fileperms_t perm, switch_memory_pool_t *pool)
Definition: switch_apr.c:411
#define SWITCH_SEEK_CUR
Definition: switch_apr.h:699
void switch_event_destroy(switch_event_t **event)
Destroy an event.
switch_status_t switch_file_close(switch_file_t *thefile)
Definition: switch_apr.c:432
char * switch_core_sprintf(_In_ switch_memory_pool_t *pool, _In_z_ _Printf_format_string_ const char *fmt,...)
printf-style style printing routine. The data is output to a string allocated from the pool ...
#define switch_assert(expr)
#define DUP_CHECK(dup)
static switch_status_t get_file_size(switch_file_handle_t *fh, const char **string)
switch_size_t switch_buffer_inuse(_In_ switch_buffer_t *buffer)
Get the in use amount of a switch_buffer_t.
void switch_buffer_destroy(switch_buffer_t **buffer)
Destroy the buffer.
SWITCH_BEGIN_EXTERN_C char * switch_mprintf(const char *zFormat,...)
#define switch_resample_create(_n, _fr, _tr, _ts, _q, _c)
#define SWITCH_UUID_FORMATTED_LENGTH
Definition: switch_apr.h:545
uint32_t switch_resample_process(switch_audio_resampler_t *resampler, int16_t *src, uint32_t srclen)
Resample one float buffer into another using specifications of a given handle.
switch_size_t switch_file_get_size(switch_file_t *thefile)
Definition: switch_apr.c:491