/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2014, Anthony Minessale II * * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * * The Initial Developer of the Original Code is * Anthony Minessale II * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Mathieu Rene * * fs_encode.c -- Encode a native file * */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #ifndef WIN32 /*GRC: #include */ #ifdef HAVE_SETRLIMIT #include #endif #endif // C #include //#include // #include // C++ //#include // Freeswitch #include /* Picky compiler */ #ifdef __ICC #pragma warning (disable:167) #endif #define PATH_MAX 4096 int encode_wav_file(int DEBUG, const char* input, int channels, int rate, int ptime, switch_codec_t* pcmu_codec, switch_codec_t* g729_codec); int encode_chunk(int DEBUG,char* buf, size_t bufsize, size_t len, int rate, switch_codec_t* codec, switch_file_handle_t fh_output); void substring(const char [], char[], int, int); static void cleanup_globals() { switch_safe_free(SWITCH_GLOBAL_dirs.conf_dir); switch_safe_free(SWITCH_GLOBAL_dirs.mod_dir); switch_safe_free(SWITCH_GLOBAL_dirs.log_dir); } int main(int argc, char *argv[]) { int i; int r = 1; switch_bool_t verbose = SWITCH_FALSE; int DEBUG = 0; const char* err = NULL; int cmd_fail = 0; const char *fmtp = ""; const char *input; int ptime = 20; int channels = 1; int rate = 8000; int bitrate = 0; switch_memory_pool_t *pool = NULL; switch_codec_t pcmu_codec = { 0 }; switch_codec_t g729_codec = { 0 }; DIR* dir = NULL; struct dirent* ent = NULL; const char* dot = NULL; int num_converted = 0; char filename[PATH_MAX]; const char* slash = ""; const char* loadable_modules[] = {"mod_dahdi_codec","mod_spandsp","mod_sndfile", "mod_native_file"}; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { case 'c': i++; if((SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.conf_dir, argv[i]); break; case 'k': i++; if((SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.log_dir, argv[i]); break; case 'm': i++; if((SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { return 255; } strcpy(SWITCH_GLOBAL_dirs.mod_dir, argv[i]); break; case 'f': fmtp = argv[++i]; break; case 'p': ptime = atoi(argv[++i]); break; case 'r': rate = atoi(argv[++i]); break; case 'b': bitrate = atoi(argv[++i]); break; case 'v': verbose = SWITCH_TRUE; DEBUG = 1; break; default: printf("Command line option not recognized: %s\n", argv[i]); cmd_fail = 1; } } else { break; } } if (DEBUG) fprintf(stderr, "GRC: Parsed arguments\n"); if (argc - i < 1 || cmd_fail) { goto usage; } input = argv[i++]; if (zstr(input)) { goto usage; } if (switch_core_init(SCF_MINIMAL, verbose, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init core [%s]\n", err); goto end; } if (DEBUG){ fprintf(stderr, "GRC: Inistialized Core\n"); fprintf(stderr, "Mod dir=%s\n", SWITCH_GLOBAL_dirs.mod_dir); } switch_loadable_module_init(SWITCH_FALSE); switch_loadable_module_load_module((char*)"", (char*)"CORE_PCM_MODULE", SWITCH_TRUE, &err); if (DEBUG) fprintf(stderr, "GRC: Inistialized CORE_PCM_MODULE: %s\n",err); switch_loadable_module_load_module((char*)"", (char*)"CORE_SPEEX_MODULE", SWITCH_TRUE, &err); if (DEBUG) fprintf(stderr, "GRC: Inistialized CORE_SPEEX_MODULE: %s\n",err); switch_loadable_module_load_module((char*)"", (char*)"CORE_SOFTTIMER_MODULE", SWITCH_TRUE, &err); if (DEBUG) fprintf(stderr, "GRC: Inistialized CORE_SOFTTIMER_MODULE: %s\n",err); if (DEBUG) fprintf(stderr, "GRC: Loadable modules: %d\n",(int)(sizeof(loadable_modules)/sizeof(loadable_modules[0]))); for (i = 0; i < (int)(sizeof(loadable_modules)/sizeof(loadable_modules[0])); i++) { if (switch_loadable_module_load_module((char*) SWITCH_GLOBAL_dirs.mod_dir, (char*)loadable_modules[i], SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Cannot init %s [%s]\n", loadable_modules[i], err); goto end; } if (DEBUG) fprintf(stderr, "GRC: Inistialized Loadable module: %s -- %s\n",(char*)loadable_modules[i],err); } if (DEBUG) fprintf(stderr, "GRC: Inistialized Loadable modules: %s\n",err); switch_core_new_memory_pool(&pool); if (DEBUG) fprintf(stderr, "GRC: Allocated memory pool\n"); if (input[strlen(input)-1] != '/') { slash = "/"; } if (DEBUG) { fprintf(stderr, "GRC: Slash: %s\n",slash); fprintf(stderr, "GRC: Input: %s\n",input); fprintf(stderr, "About to initialize PCMU codec for PCMU@%dh@%di Channels %d Bitrate %d\n", rate, ptime, channels, bitrate); } i=switch_core_codec_init_with_bitrate(&pcmu_codec, "PCMU", NULL,fmtp,rate, ptime, channels, bitrate,(uint32_t)SWITCH_CODEC_FLAG_ENCODE, NULL,pool); /* switch_codec_t*, const char*, const char*, uint32_t, int, int, uint32_t, uint32_t, const switch_codec_settings_t*, switch_memory_pool_t**/ if (DEBUG) fprintf(stderr, "i:%d\n", i); if (i != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't initialize codec for PCMU@%dh@%di\n", rate, ptime); goto end; } if (DEBUG) fprintf(stderr, "GRC: Inistialized PCMU\n"); i=0; if (DEBUG) fprintf(stderr, "About to initialize G729 codec for G729@%dh@%di Channels %d Bitrate %d\n", rate, ptime, channels, bitrate); i = switch_core_codec_init_with_bitrate(&g729_codec, "G729", NULL, fmtp, rate, ptime, channels, bitrate, SWITCH_CODEC_FLAG_ENCODE, NULL, pool); if (DEBUG) fprintf(stderr, "i:%d\n", i); if (i != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't initialize codec for G729@%dh@%di\n", rate, ptime); goto end; } if (DEBUG) fprintf(stderr, "GRC: Inistialized G.729\n"); if ((dir = opendir(input)) != NULL) { while ((ent = readdir(dir)) != NULL) { if (ent->d_type == 8) { //DT_REG if ((dot = strrchr(ent->d_name, '.')) != NULL && strcasecmp(dot, ".WAV") == 0) { sprintf(filename, "%s%s%s", input, slash, ent->d_name); if (DEBUG) printf("Converting %s\n", filename); if (encode_wav_file(DEBUG, filename, channels, rate, ptime, &pcmu_codec, &g729_codec)) { num_converted++; } else { fprintf(stderr, "Error converting %s\n", ent->d_name); goto end; } } } } } else { fprintf(stderr, "Couldn't open directory %s\n", input); goto end; } if (DEBUG) fprintf(stdout, "Done converting %d file(s).\n", num_converted); r = 0; end: if (dir) { closedir (dir); } switch_core_codec_destroy(&pcmu_codec); switch_core_codec_destroy(&g729_codec); if (pool) { switch_core_destroy_memory_pool(&pool); } cleanup_globals(); return r; usage: printf("Usage: %s [options] dir\n\n", argv[0]); printf("dir: path to directory containing .WAV files to convert\n"); printf("\t\t -c path\t\t Path to the FS configurations.\n"); printf("\t\t -k path\t\t Path to the FS log directory\n"); printf("\t\t -m path\t\t Path to the modules.\n"); printf("\t\t -f format\t\t fmtp to pass to the codec\n"); printf("\t\t -p ptime\t\t ptime to use while encoding\n"); printf("\t\t -r rate\t\t sampling rate\n"); printf("\t\t -b bitrate\t\t codec bitrate (if supported)\n"); printf("\t\t -v\t\t\t verbose\n"); cleanup_globals(); return 1; } void substring(const char s[], char sub[], int p, int l) { int c = 0; while (c < l) { sub[c] = s[p+c-1]; c++; } sub[c] = '\0'; } int encode_wav_file(int DEBUG,const char* input, int channels, int rate, int ptime, switch_codec_t* pcmu_codec, switch_codec_t* g729_codec) { //using namespace std; int pos = 0; char* charpos; int r = 1; switch_file_handle_t fh_wav = { 0 }; switch_file_handle_t fh_pcmu = { 0 }; switch_file_handle_t fh_g729 = { 0 }; char buf[2048]; char basename[PATH_MAX]; char pcmu_output[PATH_MAX]; char g729_output[PATH_MAX]; switch_size_t len = (rate*ptime)/1000; int blocksize = len; switch_assert(sizeof(buf) >= len * 2); //string tmp = input; //size_t pos = tmp.find_last_of('.'); charpos = strrchr(input,'.'); if (charpos == NULL) { fprintf(stderr, "Missing file extension in %s\n", input); return 0; } //string basename = tmp.substr(0, pos); //string pcmu_output = basename + ".PCMU"; //string g729_output = basename + ".G729"; pos = charpos - input; if (DEBUG) fprintf(stderr, "encode_wav_file:pos: %d\n", pos); //substring(input,basename,0,pos); strncpy(basename,input,pos); basename[pos]='\0'; sprintf(pcmu_output,"%s.PCMU",basename); sprintf(g729_output,"%s.G729",basename); if (DEBUG){ fprintf(stderr, "encode_wav_file:input: %s\n", input); fprintf(stderr, "encode_wav_file:basename: %s\n", basename); fprintf(stderr, "encode_wav_file:PCMU %s\n", pcmu_output); fprintf(stderr, "encode_wav_file:G729 %s\n", g729_output); } if (switch_core_file_open(&fh_wav, input, channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't open %s\n", input); goto end; } if (switch_core_file_open(&fh_pcmu, pcmu_output, channels, pcmu_codec->implementation->actual_samples_per_second, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_NATIVE, NULL) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't open %s\n", pcmu_output); goto end; } if (switch_core_file_open(&fh_g729, g729_output, channels, g729_codec->implementation->actual_samples_per_second, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_NATIVE, NULL) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Couldn't open %s\n", g729_output); goto end; } if (DEBUG) fprintf(stderr, "encode_wav_file:blocksize %d, rate %d\n", blocksize, rate); while (switch_core_file_read(&fh_wav, buf, &len) == SWITCH_STATUS_SUCCESS) { if (!encode_chunk(DEBUG,(char*)buf, sizeof(buf), len, rate, pcmu_codec, fh_pcmu) || !encode_chunk(DEBUG,(char*)buf, sizeof(buf), len, rate, g729_codec, fh_g729)) { goto end; } len = blocksize; } r = 1; end: if (fh_wav.file_interface) { switch_core_file_close(&fh_wav); } if (fh_pcmu.file_interface) { switch_core_file_close(&fh_pcmu); } if (fh_g729.file_interface) { switch_core_file_close(&fh_g729); } return r; } int encode_chunk(int DEBUG,char* buf, size_t bufsize, size_t len, int rate, switch_codec_t* codec, switch_file_handle_t fh_output) { char encode_buf[2048]; uint32_t encoded_len = bufsize; uint32_t encoded_rate = rate; unsigned int flags = 0; if (switch_core_codec_encode(codec, NULL, buf, len*2, rate, encode_buf, &encoded_len, &encoded_rate, &flags) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Codec encoder error\n"); return 0; } len = encoded_len; if (DEBUG) fprintf(stderr, "encode_chunk: len: %d\n",(int)len); if (switch_core_file_write(&fh_output, encode_buf, &len) != SWITCH_STATUS_SUCCESS) { fprintf(stderr, "Write error\n"); return 0; } if (len != encoded_len) { printf("Short write: wrote %"SWITCH_SIZE_T_FMT"/%d bytes\n", len, encoded_len); return 0; } return 1; }