static switch_status_t flite_speech_read_tts(switch_speech_handle_t *sh, void *data, size_t *datalen, switch_speech_flag_t *flags) { size_t bytes_read; flite_t *flite = (flite_t *) sh->private_info; if (!flite->audio_buffer) { int32_t len; if (flite->w) { len = flite->w->num_samples * 2; } else { len = FLITE_BLOCK_SIZE; } switch_buffer_create_dynamic(&flite->audio_buffer, FLITE_BLOCK_SIZE, len, 0); switch_assert(flite->audio_buffer); } if (flite->w) { switch_buffer_write(flite->audio_buffer, flite->w->samples, flite->w->num_samples * 2); free_wave(flite->w); } if ((bytes_read = switch_buffer_read(flite->audio_buffer, data, *datalen))) { *datalen = bytes_read; return SWITCH_STATUS_SUCCESS; } return SWITCH_STATUS_FALSE; }
static switch_status_t init_decoder(switch_codec_t *codec) { vpx_context_t *context = (vpx_context_t *)codec->private_info; vpx_codec_dec_cfg_t cfg = {0, 0, 0}; vpx_codec_flags_t dec_flags = 0; if (context->flags & SWITCH_CODEC_FLAG_DECODE && !context->decoder_init) { vp8_postproc_cfg_t ppcfg; //if (context->decoder_init) { // vpx_codec_destroy(&context->decoder); // context->decoder_init = 0; //} cfg.threads = switch_core_cpu_count(); if (!context->is_vp9) { // vp8 only dec_flags = VPX_CODEC_USE_POSTPROC; } if (vpx_codec_dec_init(&context->decoder, context->decoder_interface, &cfg, dec_flags) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec init error: [%d:%s]\n", context->encoder.err, context->encoder.err_detail); return SWITCH_STATUS_FALSE; } context->last_ts = 0; context->last_received_timestamp = 0; context->last_received_complete_picture = 0; context->decoder_init = 1; context->got_key_frame = 0; context->got_start_frame = 0; // the types of post processing to be done, should be combination of "vp8_postproc_level" ppcfg.post_proc_flag = VP8_DEBLOCK;//VP8_DEMACROBLOCK | VP8_DEBLOCK; // the strength of deblocking, valid range [0, 16] ppcfg.deblocking_level = 1; // Set deblocking settings vpx_codec_control(&context->decoder, VP8_SET_POSTPROC, &ppcfg); if (context->vpx_packet_buffer) { switch_buffer_zero(context->vpx_packet_buffer); } else { switch_buffer_create_dynamic(&context->vpx_packet_buffer, 512, 512, 0); } } return SWITCH_STATUS_SUCCESS; }
static switch_status_t start_capture(switch_core_session_t *session, unsigned int seconds, switch_media_bug_flag_t flags, const char *base) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_media_bug_t *bug; switch_status_t status; switch_codec_implementation_t read_impl = { 0 }; struct cap_cb *cb; switch_size_t bytes; switch_bind_flag_t bind_flags = 0; if (switch_channel_get_private(channel, "snapshot")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Already Running.\n"); return SWITCH_STATUS_FALSE; } if (seconds < 5) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Must be at least 5 seconds!\n"); return SWITCH_STATUS_FALSE; } switch_core_session_get_read_impl(session, &read_impl); if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; } cb = switch_core_session_alloc(session, sizeof(*cb)); cb->base = switch_core_session_strdup(session, base); bytes = read_impl.samples_per_second * seconds * 2; switch_buffer_create_dynamic(&cb->buffer, bytes, bytes, bytes); switch_mutex_init(&cb->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); if ((status = switch_core_media_bug_add(session, "snapshot", NULL, capture_callback, cb, 0, flags, &bug)) != SWITCH_STATUS_SUCCESS) { return status; } bind_flags = SBF_DIAL_ALEG | SBF_EXEC_ALEG | SBF_EXEC_SAME; switch_ivr_bind_dtmf_meta_session(session, 7, bind_flags, "snapshot::snap"); switch_channel_set_private(channel, "snapshot", bug); return SWITCH_STATUS_SUCCESS; }
void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj) { rtmp_io_tcp_t *io = (rtmp_io_tcp_t*)obj; io->base.running = 1; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: I/O Thread starting\n", io->base.profile->name); while(io->base.running) { const switch_pollfd_t *fds; int32_t numfds; int32_t i; switch_status_t status; switch_mutex_lock(io->mutex); status = switch_pollset_poll(io->pollset, 500000, &numfds, &fds); switch_mutex_unlock(io->mutex); if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_TIMEOUT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n"); continue; } else if (status == SWITCH_STATUS_TIMEOUT) { switch_cond_next(); } for (i = 0; i < numfds; i++) { if (!fds[i].client_data) { switch_socket_t *newsocket; if (switch_socket_accept(&newsocket, io->listen_socket, io->base.pool) != SWITCH_STATUS_SUCCESS) { if (io->base.running) { /* Don't spam the logs if we are shutting down */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno)); } else { return NULL; } } else { rtmp_session_t *rsession; if (switch_socket_opt_set(newsocket, SWITCH_SO_NONBLOCK, TRUE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't set socket as non-blocking\n"); } if (switch_socket_opt_set(newsocket, SWITCH_SO_TCP_NODELAY, 1)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't disable Nagle.\n"); } if (rtmp_session_request(io->base.profile, &rsession) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTMP session request failed\n"); switch_socket_close(newsocket); } else { switch_sockaddr_t *addr = NULL; char ipbuf[200]; /* Create out private data and attach it to the rtmp session structure */ rtmp_tcp_io_private_t *pvt = switch_core_alloc(rsession->pool, sizeof(*pvt)); rsession->io_private = pvt; pvt->socket = newsocket; switch_socket_create_pollfd(&pvt->pollfd, newsocket, SWITCH_POLLIN | SWITCH_POLLERR, rsession, rsession->pool); switch_pollset_add(io->pollset, pvt->pollfd); switch_buffer_create_dynamic(&pvt->sendq, 512, 1024, 0); /* Get the remote address/port info */ switch_socket_addr_get(&addr, SWITCH_TRUE, newsocket); switch_get_addr(ipbuf, sizeof(ipbuf), addr); rsession->remote_address = switch_core_strdup(rsession->pool, ipbuf); rsession->remote_port = switch_sockaddr_get_port(addr); switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Rtmp connection from %s:%i\n", rsession->remote_address, rsession->remote_port); } } } else { rtmp_session_t *rsession = (rtmp_session_t*)fds[i].client_data; rtmp_tcp_io_private_t *io_pvt = (rtmp_tcp_io_private_t*)rsession->io_private; if (fds[i].rtnevents & SWITCH_POLLOUT && switch_buffer_inuse(io_pvt->sendq) > 0) { /* Send as much remaining data as possible */ switch_size_t sendlen; const void *ptr; sendlen = switch_buffer_peek_zerocopy(io_pvt->sendq, &ptr); switch_socket_send_nonblock(io_pvt->socket, ptr, &sendlen); switch_buffer_toss(io_pvt->sendq, sendlen); if (switch_buffer_inuse(io_pvt->sendq) == 0) { /* Remove our fd from OUT polling */ rtmp_tcp_alter_pollfd(rsession, SWITCH_FALSE); } } else if (fds[i].rtnevents & SWITCH_POLLIN && rtmp_handle_data(rsession) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "Closing socket\n"); switch_mutex_lock(io->mutex); switch_pollset_remove(io->pollset, io_pvt->pollfd); switch_mutex_unlock(io->mutex); switch_socket_close(io_pvt->socket); io_pvt->socket = NULL; rtmp_session_destroy(&rsession); } } } } io->base.running = -1; switch_socket_close(io->listen_socket); return NULL; }
static switch_status_t mp4_file_open(switch_file_handle_t *handle, const char *path) { mp4_file_context_t *context; char *ext; unsigned int flags = 0; const char *tmp = NULL; if ((ext = strrchr(path, '.')) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n"); return SWITCH_STATUS_GENERR; } ext++; if ((context = switch_core_alloc(handle->memory_pool, sizeof(mp4_file_context_t))) == 0) { return SWITCH_STATUS_MEMERR; } memset(context, 0, sizeof(mp4_file_context_t)); context->offset = -100; if (handle->params && (tmp = switch_event_get_header(handle->params, "mp4v2_video_offset"))) { context->offset = atoi(tmp); } context->audio_type = MP4_ULAW_AUDIO_TYPE; // default if (handle->params && (tmp = switch_event_get_header(handle->params, "mp4v2_audio_codec"))) { if (!strcasecmp(tmp, "PCMU")) { context->audio_type = MP4_ULAW_AUDIO_TYPE; } else if (!strcasecmp(tmp, "MP3")) { context->audio_type = MP4_MP3_AUDIO_TYPE; } else if (!strcasecmp(tmp, "AAC")) { context->audio_type = MP4_MPEG4_AUDIO_TYPE; } else if (!strcasecmp(tmp, "L16")) { context->audio_type = MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE; } } switch_mutex_init(&context->mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE; if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) { flags |= SWITCH_FOPEN_READ; } else { flags |= SWITCH_FOPEN_TRUNCATE; } } if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { flags |= SWITCH_FOPEN_READ; } if ((context->fd = MP4CreateEx(path, 0, 1, 1, NULL, 0, NULL, 0)) == MP4_INVALID_FILE_HANDLE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error opening file %s\n", path); return SWITCH_STATUS_GENERR; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sample rate: %d, channels: %d\n", handle->samplerate, handle->channels); if (context->audio_type == MP4_ULAW_AUDIO_TYPE) { context->audio = MP4AddULawAudioTrack(context->fd, handle->samplerate); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.ulaw.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.ulaw.sampleSize", 8); } else if (context->audio_type == MP4_MP3_AUDIO_TYPE) { // handle->samplerate = 44100; context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_MP3_AUDIO_TYPE); MP4SetTrackName(context->fd, context->audio, ".mp3"); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); // MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd..mp3.channels", handle->channels); } else if (context->audio_type == MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE) { context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE); MP4SetTrackName(context->fd, context->audio, "lpcm"); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.lpcm.channels", handle->channels); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.lpcm.sampleSize", 16); } else if (context->audio_type == MP4_MPEG4_AUDIO_TYPE) { /* AAC object types */ #define AAC_MAIN 1 #define AAC_LOW 2 #define AAC_SSR 3 #define AAC_LTP 4 uint16_t info = 0; info |= AAC_LOW << 11; // aacObjectType (5bit) info |= get_aac_sample_rate_index(handle->samplerate) << 7; //(4bit) info |= handle->channels << 3; //(4bit) info = htons(info); context->audio = MP4AddAudioTrack(context->fd, handle->samplerate, handle->samplerate, MP4_MPEG4_AUDIO_TYPE); MP4SetTrackESConfiguration(context->fd, context->audio, (uint8_t *)&info, sizeof(info)); MP4SetTrackIntegerProperty(context->fd, context->audio, "mdia.minf.stbl.stsd.mp4a.channels", handle->channels); } handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->pos = 0; handle->private_info = context; context->pool = handle->memory_pool; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz %s\n", path, handle->samplerate, switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) ? " with VIDEO" : ""); if (switch_core_codec_init(&context->audio_codec, get_audio_codec_name(context->audio_type), NULL, NULL, handle->samplerate, 20,//ms handle->channels, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n"); goto end; } if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) { if (switch_core_codec_init(&context->video_codec, "H264", NULL, NULL, 90000, 0,//ms 1, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video Codec H264 Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Video Codec H264 Activation Fail\n"); goto end; } } if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { MP4SetAudioProfileLevel(context->fd, 0x7F); } switch_buffer_create_dynamic(&context->buf, 512, 512, 1024000); return SWITCH_STATUS_SUCCESS; end: if (context->fd) { MP4Close(context->fd, 0); context->fd = NULL; } return SWITCH_STATUS_FALSE; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { local_stream_source_t *source = obj; switch_file_handle_t fh = { 0 }; local_stream_context_t *cp; char file_buf[128] = "", path_buf[512] = ""; switch_timer_t timer = { 0 }; int fd = -1; switch_buffer_t *audio_buffer; switch_byte_t *dist_buf; switch_size_t used; int skip = 0; switch_memory_pool_t *temp_pool = NULL; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); if (source->shuffle) { skip = do_rand(); } switch_thread_rwlock_create(&source->rwlock, source->pool); if (RUNNING) { switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->name, source); switch_mutex_unlock(globals.mutex); source->ready = 1; } while (RUNNING && !source->stopped) { const char *fname; if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool"); goto done; } if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location); goto done; } switch_yield(1000000); while (RUNNING) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; if (fd > -1) { char *p; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) { *p = '\0'; } } else { close(fd); fd = -1; continue; } } else { if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { break; } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); if (switch_stristr(".loc", path_buf)) { if ((fd = open(path_buf, O_RDONLY)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); } continue; } } if (skip > 0) { skip--; continue; } fname = path_buf; fh.prebuf = source->prebuf; fh.pre_buffer_datalen = source->prebuf; if (switch_core_file_open(&fh, (char *) fname, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); continue; } if (switch_core_timer_init(&timer, source->timer_name, source->interval, source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); switch_dir_close(source->dir_handle); source->dir_handle = NULL; goto done; } while (RUNNING) { int is_open; switch_file_handle_t *use_fh = &fh; switch_core_timer_next(&timer); olen = source->samples; if (source->chime_total) { if (source->chime_counter > 0) { source->chime_counter -= source->samples; } if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) { char *val; val = source->chime_list[source->chime_cur++]; if (source->chime_cur >= source->chime_total) { source->chime_cur = 0; } if (switch_core_file_open(&source->chime_fh, (char *) val, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val); } } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (is_open) { if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } is_open = 0; } else { if (use_fh == &source->chime_fh && source->chime_max) { source->chime_max_counter += source->samples; if (source->chime_max_counter >= source->chime_max) { source->chime_max_counter = 0; switch_core_file_close(use_fh); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } switch_buffer_write(audio_buffer, abuf, olen * 2); } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); if (switch_buffer_inuse(cp->audio_buffer) > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d]\n", cp->func, cp->file, cp->line); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, dist_buf, used); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(); } } switch_dir_close(source->dir_handle); source->dir_handle = NULL; } done: if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&fh); } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&source->chime_fh); } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->name); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_buffer_destroy(&audio_buffer); if (fd > -1) { close(fd); } if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); THREADS--; switch_mutex_unlock(globals.mutex); return NULL; }
void do_telecast(switch_stream_handle_t *stream) { char *path_info = switch_event_get_header(stream->param_event, "http-path-info"); char *uuid = strdup(path_info + 4); switch_core_session_t *tsession; char *fname = "stream.mp3"; if ((fname = strchr(uuid, '/'))) { *fname++ = '\0'; } if (!(tsession = switch_core_session_locate(uuid))) { char *ref = switch_event_get_header(stream->param_event, "http-referer"); stream->write_function(stream, "Content-type: text/html\r\n\r\n<h2>Not Found!</h2>\n" "<META http-equiv=\"refresh\" content=\"1;URL=%s\">", ref); } else { switch_media_bug_t *bug = NULL; switch_buffer_t *buffer = NULL; switch_mutex_t *mutex; switch_channel_t *channel = switch_core_session_get_channel(tsession); lame_global_flags *gfp = NULL; switch_codec_implementation_t read_impl = { 0 }; switch_core_session_get_read_impl(tsession, &read_impl); if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stepping into media path so this will work!\n"); switch_ivr_media(uuid, SMF_REBRIDGE); } if (!(gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto end; } lame_set_num_channels(gfp, read_impl.number_of_channels); lame_set_in_samplerate(gfp, read_impl.actual_samples_per_second); lame_set_brate(gfp, 16 * (read_impl.actual_samples_per_second / 8000) * read_impl.number_of_channels); lame_set_mode(gfp, 3); lame_set_quality(gfp, 2); lame_set_errorf(gfp, log_error); lame_set_debugf(gfp, log_debug); lame_set_msgf(gfp, log_msg); lame_set_bWriteVbrTag(gfp, 0); lame_mp3_tags_fid(gfp, NULL); lame_init_params(gfp); lame_print_config(gfp); switch_mutex_init(&mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); switch_buffer_create_dynamic(&buffer, 1024, 2048, 0); switch_buffer_add_mutex(buffer, mutex); if (switch_core_media_bug_add(tsession, "telecast", NULL, telecast_callback, buffer, 0, SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING, &bug) != SWITCH_STATUS_SUCCESS) { goto end; } stream->write_function(stream, "Content-type: audio/mpeg\r\n" "Content-Disposition: inline; filename=\"%s\"\r\n\r\n", fname); while (switch_channel_ready(channel)) { unsigned char mp3buf[TC_BUFFER_SIZE] = ""; int rlen; uint8_t buf[1024]; switch_size_t bytes = 0; if (switch_buffer_inuse(buffer) >= 1024) { switch_buffer_lock(buffer); bytes = switch_buffer_read(buffer, buf, sizeof(buf)); switch_buffer_unlock(buffer); } else { if (!bytes) { switch_cond_next(); continue; } memset(buf, 0, bytes); } if ((rlen = lame_encode_buffer(gfp, (void *) buf, NULL, bytes / 2, mp3buf, sizeof(mp3buf))) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); goto end; } if (rlen) { if (stream->raw_write_function(stream, mp3buf, rlen)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected\n"); goto end; } } } end: switch_safe_free(uuid); if (gfp) { lame_close(gfp); gfp = NULL; } if (bug) { switch_core_media_bug_remove(tsession, &bug); } if (buffer) { switch_buffer_destroy(&buffer); } switch_core_session_rwunlock(tsession); } }
/** * Wraps file with interface that can be controlled by fileman flags * @param handle * @param path the file to play * @return SWITCH_STATUS_SUCCESS if opened */ static switch_status_t fileman_file_open(switch_file_handle_t *handle, const char *path) { int start_offset_ms = 0; switch_status_t status = SWITCH_STATUS_FALSE; struct fileman_file_context *context = switch_core_alloc(handle->memory_pool, sizeof(*context)); handle->private_info = context; if (handle->params) { const char *id = switch_event_get_header(handle->params, "id"); const char *uuid = switch_event_get_header(handle->params, "session"); const char *start_offset_ms_str = switch_event_get_header(handle->params, "start_offset_ms"); if (!zstr(id)) { context->id = switch_core_strdup(handle->memory_pool, id); } if (!zstr(uuid)) { context->uuid = switch_core_strdup(handle->memory_pool, uuid); } if (!zstr(start_offset_ms_str) && switch_is_number(start_offset_ms_str)) { start_offset_ms = atoi(start_offset_ms_str); if (start_offset_ms < 0) { start_offset_ms = 0; } } } switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Got path %s\n", path); if ((status = switch_core_file_open(&context->fh, path, handle->channels, handle->samplerate, handle->flags, NULL)) != SWITCH_STATUS_SUCCESS) { return status; } /* set up handle for external control */ if (!context->id) { /* use filename as ID */ context->id = switch_core_strdup(handle->memory_pool, path); } switch_mutex_lock(fileman_globals.mutex); if (!switch_core_hash_find(fileman_globals.hash, context->id)) { switch_core_hash_insert(fileman_globals.hash, context->id, handle); } else { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_WARNING, "Duplicate fileman ID: %s\n", context->id); return SWITCH_STATUS_FALSE; } switch_mutex_unlock(fileman_globals.mutex); context->max_frame_len = (handle->samplerate / 1000 * SWITCH_MAX_INTERVAL); switch_zmalloc(context->abuf, FILE_STARTBYTES * sizeof(*context->abuf)); if (!context->fh.audio_buffer) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Create audio buffer\n"); switch_buffer_create_dynamic(&context->fh.audio_buffer, FILE_BLOCKSIZE, FILE_BUFSIZE, 0); switch_assert(context->fh.audio_buffer); } handle->samples = context->fh.samples; handle->format = context->fh.format; handle->sections = context->fh.sections; handle->seekable = context->fh.seekable; handle->speed = context->fh.speed; handle->vol = context->fh.vol; handle->offset_pos = context->fh.offset_pos; handle->interval = context->fh.interval; if (switch_test_flag((&context->fh), SWITCH_FILE_NATIVE)) { switch_set_flag(handle, SWITCH_FILE_NATIVE); } else { switch_clear_flag(handle, SWITCH_FILE_NATIVE); } if (handle->params && switch_true(switch_event_get_header(handle->params, "pause"))) { switch_set_flag(handle, SWITCH_FILE_PAUSE); } if (handle->seekable && start_offset_ms) { unsigned int pos = 0; int32_t target = start_offset_ms * (handle->samplerate / 1000); switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "seek to position %d\n", target); switch_core_file_seek(&context->fh, &pos, target, SEEK_SET); } return status; }
SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) { switch_status_t status = SWITCH_STATUS_FALSE; switch_frame_t *enc_frame = NULL, *write_frame = frame; unsigned int flag = 0, need_codec = 0, perfect = 0, do_bugs = 0, do_write = 0, do_resample = 0, ptime_mismatch = 0, pass_cng = 0, resample = 0; int did_write_resample = 0; switch_assert(session != NULL); switch_assert(frame != NULL); if (!switch_channel_ready(session->channel)) { return SWITCH_STATUS_FALSE; } if (switch_mutex_trylock(session->codec_write_mutex) == SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(session->codec_write_mutex); } else { return SWITCH_STATUS_SUCCESS; } if (switch_test_flag(frame, SFF_CNG)) { if (switch_channel_test_flag(session->channel, CF_ACCEPT_CNG)) { pass_cng = 1; } else { return SWITCH_STATUS_SUCCESS; } } if (!(session->write_codec && switch_core_codec_ready(session->write_codec)) && !pass_cng) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no write codec.\n", switch_channel_get_name(session->channel)); switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); return SWITCH_STATUS_FALSE; } if (switch_channel_test_flag(session->channel, CF_HOLD)) { return SWITCH_STATUS_SUCCESS; } if (switch_test_flag(frame, SFF_PROXY_PACKET) || pass_cng) { /* Fast PASS! */ switch_mutex_lock(session->codec_write_mutex); status = perform_write(session, frame, flag, stream_id); switch_mutex_unlock(session->codec_write_mutex); return status; } switch_mutex_lock(session->codec_write_mutex); if (!(frame->codec && frame->codec->implementation)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has received a bad frame with no codec!\n", switch_channel_get_name(session->channel)); switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_mutex_unlock(session->codec_write_mutex); return SWITCH_STATUS_FALSE; } switch_assert(frame->codec != NULL); switch_assert(frame->codec->implementation != NULL); if (!(switch_core_codec_ready(session->write_codec) && frame->codec) || !switch_channel_ready(session->channel) || !switch_channel_media_ready(session->channel)) { switch_mutex_unlock(session->codec_write_mutex); return SWITCH_STATUS_FALSE; } switch_mutex_lock(session->write_codec->mutex); switch_mutex_lock(frame->codec->mutex); if (!(switch_core_codec_ready(session->write_codec) && switch_core_codec_ready(frame->codec))) goto error; if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) { if (session->write_impl.codec_id == frame->codec->implementation->codec_id || session->write_impl.microseconds_per_packet != frame->codec->implementation->microseconds_per_packet) { ptime_mismatch = TRUE; if ((switch_test_flag(frame->codec, SWITCH_CODEC_FLAG_PASSTHROUGH) || switch_test_flag(session->read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH)) || switch_channel_test_flag(session->channel, CF_PASSTHRU_PTIME_MISMATCH)) { status = perform_write(session, frame, flags, stream_id); goto error; } } need_codec = TRUE; } if (session->write_codec && !frame->codec) { need_codec = TRUE; } if (session->bugs && !need_codec) { do_bugs = TRUE; need_codec = TRUE; } if (frame->codec->implementation->actual_samples_per_second != session->write_impl.actual_samples_per_second) { need_codec = TRUE; do_resample = TRUE; } if (switch_test_flag(session, SSF_WRITE_TRANSCODE) && !need_codec && switch_core_codec_ready(session->write_codec)) { switch_core_session_t *other_session; const char *uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_SIGNAL_BOND_VARIABLE); if (uuid && (other_session = switch_core_session_locate(uuid))) { switch_set_flag(other_session, SSF_READ_CODEC_RESET); switch_set_flag(other_session, SSF_READ_CODEC_RESET); switch_set_flag(other_session, SSF_WRITE_CODEC_RESET); switch_core_session_rwunlock(other_session); } switch_clear_flag(session, SSF_WRITE_TRANSCODE); } if (switch_test_flag(session, SSF_WRITE_CODEC_RESET)) { switch_core_codec_reset(session->write_codec); switch_clear_flag(session, SSF_WRITE_CODEC_RESET); } if (!need_codec) { do_write = TRUE; write_frame = frame; goto done; } if (!switch_test_flag(session, SSF_WARN_TRANSCODE)) { switch_core_session_message_t msg = { 0 }; msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY; switch_core_session_receive_message(session, &msg); switch_set_flag(session, SSF_WARN_TRANSCODE); } if (frame->codec) { session->raw_write_frame.datalen = session->raw_write_frame.buflen; status = switch_core_codec_decode(frame->codec, session->write_codec, frame->data, frame->datalen, session->write_impl.actual_samples_per_second, session->raw_write_frame.data, &session->raw_write_frame.datalen, &session->raw_write_frame.rate, &frame->flags); if (do_resample && status == SWITCH_STATUS_SUCCESS) { status = SWITCH_STATUS_RESAMPLE; } switch (status) { case SWITCH_STATUS_RESAMPLE: resample++; write_frame = &session->raw_write_frame; write_frame->rate = frame->codec->implementation->actual_samples_per_second; if (!session->write_resampler) { switch_mutex_lock(session->resample_mutex); status = switch_resample_create(&session->write_resampler, frame->codec->implementation->actual_samples_per_second, session->write_impl.actual_samples_per_second, session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); switch_mutex_unlock(session->resample_mutex); if (status != SWITCH_STATUS_SUCCESS) { goto done; } } break; case SWITCH_STATUS_SUCCESS: session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t); session->raw_write_frame.timestamp = frame->timestamp; session->raw_write_frame.rate = frame->rate; session->raw_write_frame.m = frame->m; session->raw_write_frame.ssrc = frame->ssrc; session->raw_write_frame.seq = frame->seq; session->raw_write_frame.payload = frame->payload; session->raw_write_frame.flags = 0; if (switch_test_flag(frame, SFF_PLC)) { session->raw_write_frame.flags |= SFF_PLC; } write_frame = &session->raw_write_frame; break; case SWITCH_STATUS_BREAK: status = SWITCH_STATUS_SUCCESS; goto error; case SWITCH_STATUS_NOOP: if (session->write_resampler) { switch_mutex_lock(session->resample_mutex); switch_resample_destroy(&session->write_resampler); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n"); switch_mutex_unlock(session->resample_mutex); } write_frame = frame; status = SWITCH_STATUS_SUCCESS; break; default: if (status == SWITCH_STATUS_NOT_INITALIZED) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); goto error; } if (ptime_mismatch) { status = perform_write(session, frame, flags, stream_id); status = SWITCH_STATUS_SUCCESS; goto error; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error!\n", frame->codec->codec_interface->interface_name); goto error; } } if (session->write_resampler) { short *data = write_frame->data; switch_mutex_lock(session->resample_mutex); if (session->write_resampler) { switch_resample_process(session->write_resampler, data, write_frame->datalen / 2); memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2); write_frame->samples = session->write_resampler->to_len; write_frame->datalen = write_frame->samples * 2; write_frame->rate = session->write_resampler->to_rate; did_write_resample = 1; } switch_mutex_unlock(session->resample_mutex); } if (session->bugs) { switch_media_bug_t *bp; int prune = 0; switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { switch_bool_t ok = SWITCH_TRUE; if (!bp->ready) { continue; } if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { continue; } if (switch_test_flag(bp, SMBF_PRUNE)) { prune++; continue; } if (switch_test_flag(bp, SMBF_WRITE_STREAM)) { switch_mutex_lock(bp->write_mutex); switch_buffer_write(bp->raw_write_buffer, write_frame->data, write_frame->datalen); switch_mutex_unlock(bp->write_mutex); if (bp->callback) { ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE); } } if (switch_test_flag(bp, SMBF_WRITE_REPLACE)) { do_bugs = 0; if (bp->callback) { bp->write_replace_frame_in = write_frame; bp->write_replace_frame_out = write_frame; if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_REPLACE)) == SWITCH_TRUE) { write_frame = bp->write_replace_frame_out; } } } if (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) { ok = SWITCH_FALSE; } if (ok == SWITCH_FALSE) { switch_set_flag(bp, SMBF_PRUNE); prune++; } } switch_thread_rwlock_unlock(session->bug_rwlock); if (prune) { switch_core_media_bug_prune(session); } } if (do_bugs) { do_write = TRUE; write_frame = frame; goto done; } if (session->write_codec) { if (!ptime_mismatch && write_frame->codec && write_frame->codec->implementation && write_frame->codec->implementation->decoded_bytes_per_packet == session->write_impl.decoded_bytes_per_packet) { perfect = TRUE; } if (perfect) { if (write_frame->datalen < session->write_impl.decoded_bytes_per_packet) { memset(write_frame->data, 255, session->write_impl.decoded_bytes_per_packet - write_frame->datalen); write_frame->datalen = session->write_impl.decoded_bytes_per_packet; } enc_frame = write_frame; session->enc_write_frame.datalen = session->enc_write_frame.buflen; status = switch_core_codec_encode(session->write_codec, frame->codec, enc_frame->data, enc_frame->datalen, session->write_impl.actual_samples_per_second, session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag); switch (status) { case SWITCH_STATUS_RESAMPLE: resample++; /* switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 2\n"); */ case SWITCH_STATUS_SUCCESS: session->enc_write_frame.codec = session->write_codec; session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); if (frame->codec->implementation->samples_per_packet != session->write_impl.samples_per_packet) { session->enc_write_frame.timestamp = 0; } else { session->enc_write_frame.timestamp = frame->timestamp; } session->enc_write_frame.payload = session->write_impl.ianacode; session->enc_write_frame.m = frame->m; session->enc_write_frame.ssrc = frame->ssrc; session->enc_write_frame.seq = frame->seq; write_frame = &session->enc_write_frame; break; case SWITCH_STATUS_NOOP: enc_frame->codec = session->write_codec; enc_frame->samples = enc_frame->datalen / sizeof(int16_t); enc_frame->timestamp = frame->timestamp; enc_frame->m = frame->m; enc_frame->seq = frame->seq; enc_frame->ssrc = frame->ssrc; enc_frame->payload = enc_frame->codec->implementation->ianacode; write_frame = enc_frame; status = SWITCH_STATUS_SUCCESS; break; case SWITCH_STATUS_NOT_INITALIZED: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); write_frame = NULL; goto error; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error!\n", session->read_codec->codec_interface->interface_name); write_frame = NULL; goto error; } if (flag & SFF_CNG) { switch_set_flag(write_frame, SFF_CNG); } status = perform_write(session, write_frame, flags, stream_id); goto error; } else { if (!session->raw_write_buffer) { switch_size_t bytes_per_packet = session->write_impl.decoded_bytes_per_packet; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Engaging Write Buffer at %u bytes to accommodate %u->%u\n", (uint32_t) bytes_per_packet, write_frame->datalen, session->write_impl.decoded_bytes_per_packet); if ((status = switch_buffer_create_dynamic(&session->raw_write_buffer, bytes_per_packet * SWITCH_BUFFER_BLOCK_FRAMES, bytes_per_packet * SWITCH_BUFFER_START_FRAMES, 0)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Write Buffer Failed!\n"); goto error; } } if (!(switch_buffer_write(session->raw_write_buffer, write_frame->data, write_frame->datalen))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Write Buffer %u bytes Failed!\n", write_frame->datalen); status = SWITCH_STATUS_MEMERR; goto error; } status = SWITCH_STATUS_SUCCESS; while (switch_buffer_inuse(session->raw_write_buffer) >= session->write_impl.decoded_bytes_per_packet) { int rate; if (switch_channel_down(session->channel) || !session->raw_write_buffer) { goto error; } if ((session->raw_write_frame.datalen = (uint32_t) switch_buffer_read(session->raw_write_buffer, session->raw_write_frame.data, session->write_impl.decoded_bytes_per_packet)) == 0) { goto error; } enc_frame = &session->raw_write_frame; session->raw_write_frame.rate = session->write_impl.actual_samples_per_second; session->enc_write_frame.datalen = session->enc_write_frame.buflen; session->enc_write_frame.timestamp = 0; if (frame->codec && frame->codec->implementation && switch_core_codec_ready(frame->codec)) { rate = frame->codec->implementation->actual_samples_per_second; } else { rate = session->write_impl.actual_samples_per_second; } status = switch_core_codec_encode(session->write_codec, frame->codec, enc_frame->data, enc_frame->datalen, rate, session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag); switch (status) { case SWITCH_STATUS_RESAMPLE: resample++; session->enc_write_frame.codec = session->write_codec; session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); session->enc_write_frame.m = frame->m; session->enc_write_frame.ssrc = frame->ssrc; session->enc_write_frame.payload = session->write_impl.ianacode; write_frame = &session->enc_write_frame; if (!session->write_resampler) { switch_mutex_lock(session->resample_mutex); if (!session->write_resampler) { status = switch_resample_create(&session->write_resampler, frame->codec->implementation->actual_samples_per_second, session->write_impl.actual_samples_per_second, session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); } switch_mutex_unlock(session->resample_mutex); if (status != SWITCH_STATUS_SUCCESS) { goto done; } } break; case SWITCH_STATUS_SUCCESS: session->enc_write_frame.codec = session->write_codec; session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); session->enc_write_frame.m = frame->m; session->enc_write_frame.ssrc = frame->ssrc; session->enc_write_frame.payload = session->write_impl.ianacode; write_frame = &session->enc_write_frame; break; case SWITCH_STATUS_NOOP: if (session->write_resampler) { switch_mutex_lock(session->resample_mutex); if (session->write_resampler) { switch_resample_destroy(&session->write_resampler); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n"); } switch_mutex_unlock(session->resample_mutex); } enc_frame->codec = session->write_codec; enc_frame->samples = enc_frame->datalen / sizeof(int16_t); enc_frame->m = frame->m; enc_frame->ssrc = frame->ssrc; enc_frame->payload = enc_frame->codec->implementation->ianacode; write_frame = enc_frame; status = SWITCH_STATUS_SUCCESS; break; case SWITCH_STATUS_NOT_INITALIZED: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); write_frame = NULL; goto error; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error %d!\n", session->read_codec->codec_interface->interface_name, status); write_frame = NULL; goto error; } if (!did_write_resample && session->read_resampler) { short *data = write_frame->data; switch_mutex_lock(session->resample_mutex); if (session->read_resampler) { switch_resample_process(session->read_resampler, data, write_frame->datalen / 2); memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); write_frame->samples = session->read_resampler->to_len; write_frame->datalen = session->read_resampler->to_len * 2; write_frame->rate = session->read_resampler->to_rate; } switch_mutex_unlock(session->resample_mutex); } if (flag & SFF_CNG) { switch_set_flag(write_frame, SFF_CNG); } if (ptime_mismatch || resample) { write_frame->timestamp = 0; } if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) { break; } } goto error; } } done: if (ptime_mismatch || resample) { write_frame->timestamp = 0; } if (do_write) { status = perform_write(session, write_frame, flags, stream_id); } error: switch_mutex_unlock(session->write_codec->mutex); switch_mutex_unlock(frame->codec->mutex); switch_mutex_unlock(session->codec_write_mutex); return status; }
static switch_status_t portaudio_stream_file_open(switch_file_handle_t *handle, const char *path) { portaudio_stream_context_t *context; portaudio_stream_source_t *source; switch_memory_pool_t *pool; switch_status_t status = SWITCH_STATUS_FALSE; switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; uint32_t rate = PREFERRED_RATE; char *npath; int devNumber; int tmp; handle->pre_buffer_datalen = 0; if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing! (yet)\n"); return status; } npath = switch_core_strdup(module_pool, path); tmp = handle->samplerate; if (tmp == 8000 || tmp == 16000 || tmp == 32000 || tmp == 48000) { rate = tmp; } if (*path == '#') { devNumber = get_dev_by_number(npath + 1, 1); } else { devNumber = get_dev_by_name(npath, 1); } npath = switch_mprintf("device-%d at %d", devNumber, rate); switch_mutex_lock(globals.mutex); source = switch_core_hash_find(globals.source_hash, npath); /* dev isnt there, try to start thread */ if (!source) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " source isnt Created, create and start thread!\n"); if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, " :S no pool\n"); } else { source = switch_core_alloc(pool, sizeof(*source)); if (source != NULL) { source->pool = pool; source->sourcedev = devNumber; source->sourcename = switch_core_strdup(source->pool, npath); source->rate = rate; source->interval = 20; source->channels = 1; source->timer_name = "soft"; source->prebuf = DEFAULT_PREBUFFER_SIZE; source->stopped = 0; source->ready = 0; source->samples = switch_samples_per_packet(source->rate, source->interval); switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool); switch_threadattr_create(&thd_attr, source->pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool); } } } switch_mutex_unlock(globals.mutex); switch_yield(1000000); /* dev already engaged */ if (source) { /*wait for source to be ready */ while (source->ready == 0) { switch_yield(100000); } if (switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error rwlock !\n"); source = NULL; } } if (source) { status = SWITCH_STATUS_SUCCESS; if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error allocating context!\n"); status = SWITCH_STATUS_MEMERR; } else { /* everything goes fine at this point */ handle->samples = 0; handle->samplerate = source->rate; handle->channels = 1; handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->private_info = context; handle->interval = source->interval; switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); status = SWITCH_STATUS_MEMERR; } else { /* context created... then continue */ context->source = source; context->file = handle->file; context->func = handle->func; context->line = handle->line; context->handle = handle; switch_mutex_lock(source->mutex); context->next = source->context_list; source->context_list = context; source->total++; switch_mutex_unlock(source->mutex); } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path); status = SWITCH_STATUS_FALSE; } return status; }
SWITCH_DECLARE(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) { char *ext; switch_status_t status = SWITCH_STATUS_FALSE; char stream_name[128] = ""; char *rhs = NULL; const char *spool_path = NULL; int is_stream = 0; char *fp = NULL; int to = 0; if (switch_test_flag(fh, SWITCH_FILE_OPEN)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Handle already open\n"); return SWITCH_STATUS_FALSE; } fh->samples_in = 0; if (!fh->samplerate) { if (!(fh->samplerate = rate)) { fh->samplerate = 8000; } } if (zstr(file_path)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Filename\n"); return SWITCH_STATUS_FALSE; } fh->flags = flags; if (pool) { fh->memory_pool = pool; } else { if ((status = switch_core_new_memory_pool(&fh->memory_pool)) != SWITCH_STATUS_SUCCESS) { UNPROTECT_INTERFACE(fh->file_interface); return status; } switch_set_flag(fh, SWITCH_FILE_FLAG_FREE_POOL); } if (*file_path == '{') { char *timeout; char *new_fp; fp = switch_core_strdup(fh->memory_pool, file_path); if (switch_event_create_brackets(fp, '{', '}', ',', &fh->params, &new_fp, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) { if ((timeout = switch_event_get_header(fh->params, "timeout"))) { if ((to = atoi(timeout)) < 1) { to = 0; } } } else { new_fp = fp; } file_path = new_fp; } if (switch_directory_exists(file_path, fh->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] is a directory not a file.\n", file_path); status = SWITCH_STATUS_GENERR; goto fail; } if ((rhs = strstr(file_path, SWITCH_URL_SEPARATOR))) { switch_copy_string(stream_name, file_path, (rhs + 1) - file_path); ext = stream_name; file_path = rhs + 3; fh->file_path = switch_core_strdup(fh->memory_pool, file_path); is_stream = 1; } else { if ((flags & SWITCH_FILE_FLAG_WRITE)) { char *p, *e; fh->file_path = switch_core_strdup(fh->memory_pool, file_path); p = fh->file_path; if (*p == '[' && *(p + 1) == *SWITCH_PATH_SEPARATOR) { e = switch_find_end_paren(p, '[', ']'); if (e) { *e = '\0'; spool_path = p + 1; fh->file_path = e + 1; } } if (!spool_path) { spool_path = switch_core_get_variable_pdup(SWITCH_AUDIO_SPOOL_PATH_VARIABLE, fh->memory_pool); } file_path = fh->file_path; } if ((ext = strrchr(file_path, '.')) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown file Format [%s]\n", file_path); switch_goto_status(SWITCH_STATUS_FALSE, fail); } ext++; fh->file_path = switch_core_strdup(fh->memory_pool, file_path); } if ((fh->file_interface = switch_loadable_module_get_file_interface(ext)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid file format [%s] for [%s]!\n", ext, file_path); switch_goto_status(SWITCH_STATUS_GENERR, fail); } fh->file = file; fh->func = func; fh->line = line; if (spool_path) { char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; switch_uuid_t uuid; switch_uuid_get(&uuid); switch_uuid_format(uuid_str, &uuid); fh->spool_path = switch_core_sprintf(fh->memory_pool, "%s%s%s.%s", spool_path, SWITCH_PATH_SEPARATOR, uuid_str, ext); } else { fh->spool_path = NULL; } if (rhs) { fh->handler = switch_core_strdup(fh->memory_pool, rhs); } else { fh->handler = NULL; } if (channels) { fh->channels = channels; } else { fh->channels = 1; } file_path = fh->spool_path ? fh->spool_path : fh->file_path; if ((status = fh->file_interface->file_open(fh, file_path)) != SWITCH_STATUS_SUCCESS) { if (fh->spool_path) { 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); } UNPROTECT_INTERFACE(fh->file_interface); switch_goto_status(status, fail); } fh->real_channels = fh->channels; if (channels) { fh->channels = channels; } if ((flags & SWITCH_FILE_FLAG_WRITE) && !is_stream && (status = switch_file_exists(file_path, fh->memory_pool)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] not created!\n", file_path); fh->file_interface->file_close(fh); UNPROTECT_INTERFACE(fh->file_interface); switch_goto_status(status, fail); } if (to) { fh->max_samples = (fh->samplerate / 1000) * to; } if ((flags & SWITCH_FILE_FLAG_READ)) { fh->native_rate = fh->samplerate; } else { fh->native_rate = rate; } if (fh->samplerate && rate && fh->samplerate != rate) { 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); if ((flags & SWITCH_FILE_FLAG_READ)) { fh->samplerate = rate; } } if (fh->pre_buffer_datalen) { //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Prebuffering %d bytes\n", (int)fh->pre_buffer_datalen); switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels, 0); fh->pre_buffer_data = switch_core_alloc(fh->memory_pool, fh->pre_buffer_datalen * fh->channels); } if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) { 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"); } switch_set_flag(fh, SWITCH_FILE_OPEN); return status; fail: switch_clear_flag(fh, SWITCH_FILE_OPEN); if (fh->params) { switch_event_destroy(&fh->params); } fh->samples_in = 0; fh->max_samples = 0; if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) { switch_core_destroy_memory_pool(&fh->memory_pool); } return status; }
SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len) { switch_status_t status = SWITCH_STATUS_FALSE; switch_size_t want, orig_len = *len; switch_assert(fh != NULL); switch_assert(fh->file_interface != NULL); if (!switch_test_flag(fh, SWITCH_FILE_OPEN)) { return SWITCH_STATUS_FALSE; } top: if (fh->max_samples > 0 && fh->samples_in >= (switch_size_t)fh->max_samples) { *len = 0; return SWITCH_STATUS_FALSE; } if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2 * fh->channels) { *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels; return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; } if (switch_test_flag(fh, SWITCH_FILE_DONE)) { switch_clear_flag(fh, SWITCH_FILE_DONE); *len = 0; return SWITCH_STATUS_FALSE; } want = *len; more: if (fh->pre_buffer) { switch_size_t rlen; int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE); if (!switch_test_flag(fh, SWITCH_FILE_BUFFER_DONE)) { rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2 / fh->real_channels; if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2 * fh->channels) { if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) { return SWITCH_STATUS_BREAK; } if (status != SWITCH_STATUS_SUCCESS || !rlen) { switch_set_flag(fh, SWITCH_FILE_BUFFER_DONE); } else { fh->samples_in += rlen; if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->real_channels, fh->channels); } switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2 * fh->channels); } } } rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2 * fh->channels); *len = asis ? rlen : rlen / 2 / fh->channels; if (*len == 0) { switch_set_flag(fh, SWITCH_FILE_DONE); goto top; } else { status = SWITCH_STATUS_SUCCESS; } } else { if ((status = fh->file_interface->file_read(fh, data, len)) == SWITCH_STATUS_BREAK) { return SWITCH_STATUS_BREAK; } if (status != SWITCH_STATUS_SUCCESS || !*len) { switch_set_flag(fh, SWITCH_FILE_DONE); goto top; } fh->samples_in += *len; if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels); } } if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) { if (!fh->resampler) { if (switch_resample_create(&fh->resampler, fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); return SWITCH_STATUS_GENERR; } } switch_resample_process(fh->resampler, data, (uint32_t) *len); if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) { if (!fh->buffer) { int factor = fh->resampler->to_len * fh->samplerate / 1000; switch_buffer_create_dynamic(&fh->buffer, factor, factor, 0); switch_assert(fh->buffer); } if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2 * fh->channels) { void *mem; fh->dbuflen = fh->resampler->to_len * 2 * fh->channels; mem = realloc(fh->dbuf, fh->dbuflen); switch_assert(mem); fh->dbuf = mem; } switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen); memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels); switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2 * fh->channels); if (switch_buffer_inuse(fh->buffer) < want * 2 * fh->channels) { *len = want; goto more; } *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels; } else { memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels); *len = fh->resampler->to_len; } } return status; }
SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle_t *sh, void *data, switch_size_t *datalen, switch_speech_flag_t *flags) { switch_status_t status; switch_size_t want, orig_len = *datalen; switch_assert(sh != NULL); want = *datalen; top: if (sh->buffer && (switch_buffer_inuse(sh->buffer) >= orig_len || switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE))) { if ((*datalen = switch_buffer_read(sh->buffer, data, orig_len))) { return SWITCH_STATUS_SUCCESS; } } if (switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE)) { switch_clear_flag(sh, SWITCH_SPEECH_FLAG_DONE); *datalen = 0; return SWITCH_STATUS_BREAK; } more: if ((status = sh->speech_interface->speech_read_tts(sh, data, datalen, flags)) != SWITCH_STATUS_SUCCESS) { switch_set_flag(sh, SWITCH_SPEECH_FLAG_DONE); goto top; } if (sh->native_rate && sh->samplerate && sh->native_rate != sh->samplerate) { if (!sh->resampler) { if (switch_resample_create(&sh->resampler, sh->native_rate, sh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); return SWITCH_STATUS_GENERR; } } switch_resample_process(sh->resampler, data, (uint32_t)(*datalen / 2)); if (sh->resampler->to_len < want / 2 || sh->resampler->to_len > orig_len / 2) { if (!sh->buffer) { int factor = sh->resampler->to_len * sh->samplerate / 1000; switch_buffer_create_dynamic(&sh->buffer, factor, factor, 0); switch_assert(sh->buffer); } if (!sh->dbuf || sh->dbuflen < sh->resampler->to_len * 2) { sh->dbuflen = sh->resampler->to_len * 2; sh->dbuf = switch_core_alloc(sh->memory_pool, sh->dbuflen); } switch_assert(sh->resampler->to_len <= sh->dbuflen); memcpy((int16_t *) sh->dbuf, sh->resampler->to, sh->resampler->to_len * 2); switch_buffer_write(sh->buffer, sh->dbuf, sh->resampler->to_len * 2); if (switch_buffer_inuse(sh->buffer) < want) { *datalen = want; goto more; } *datalen = switch_buffer_read(sh->buffer, data, orig_len); status = SWITCH_STATUS_SUCCESS; } else { memcpy(data, sh->resampler->to, sh->resampler->to_len * 2); *datalen = sh->resampler->to_len * 2; status = SWITCH_STATUS_SUCCESS; } } return status; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { local_stream_source_t *source = obj; switch_file_handle_t fh = { 0 }; local_stream_context_t *cp; char file_buf[128] = "", path_buf[512] = "", last_path[512], png_buf[512] = "", tmp_buf[512] = ""; switch_timer_t timer = { 0 }; int fd = -1; switch_buffer_t *audio_buffer; switch_byte_t *dist_buf; switch_size_t used; int skip = 0; switch_memory_pool_t *temp_pool = NULL; uint32_t dir_count = 0, do_shuffle = 0; char *p; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } if (source->shuffle) { do_shuffle = 1; } switch_queue_create(&source->video_q, 500, source->pool); switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); switch_thread_rwlock_create(&source->rwlock, source->pool); if (RUNNING) { switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->name, source); switch_mutex_unlock(globals.mutex); source->ready = 1; } while (RUNNING && !source->stopped) { const char *fname; if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool"); goto done; } if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location); goto done; } if (fd > -1) { dir_count = 0; while (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { dir_count++; } lseek(fd, 0, SEEK_SET); } else { dir_count = switch_dir_count(source->dir_handle); } if (do_shuffle) { skip = do_rand(dir_count); do_shuffle = 0; } switch_yield(1000000); while (RUNNING && !source->stopped) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; const char *artist = NULL, *title = NULL; if (fd > -1) { char *pb; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((pb = strchr(path_buf, '\r')) || (pb = strchr(path_buf, '\n'))) { *pb = '\0'; } } else { close(fd); fd = -1; continue; } } else { if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { break; } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); if (switch_stristr(".loc", path_buf)) { if ((fd = open(path_buf, O_RDONLY)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); } continue; } } if (dir_count > 1 && !strcmp(last_path, path_buf)) { continue; } if (skip > 0) { skip--; continue; } switch_set_string(last_path, path_buf); fname = path_buf; fh.prebuf = source->prebuf; fh.pre_buffer_datalen = source->prebuf; if (switch_core_file_open(&fh, (char *) fname, source->channels, source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); continue; } if (switch_core_file_has_video(&fh)) { flush_video_queue(source->video_q); } if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); switch_dir_close(source->dir_handle); source->dir_handle = NULL; goto done; } switch_img_free(&source->cover_art); switch_set_string(tmp_buf, path_buf); if ((p = strrchr(tmp_buf, '/'))) { *p++ = '\0'; switch_snprintf(png_buf, sizeof(png_buf), "%s/art/%s.png", tmp_buf, p); if (switch_file_exists(png_buf, source->pool) == SWITCH_STATUS_SUCCESS) { source->cover_art = switch_img_read_png(png_buf, SWITCH_IMG_FMT_I420); } } source->serno++; switch_safe_free(source->banner_txt); title = artist = NULL; switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_ARTIST, &artist); switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_TITLE, &title); if (title && (source->cover_art || switch_core_file_has_video(&fh))) { const char *format = "#cccccc:#333333:FreeSans.ttf:3%:"; if (artist) { source->banner_txt = switch_mprintf("%s%s (%s)", format, title, artist); } else { source->banner_txt = switch_mprintf("%s%s", format, title); } } while (RUNNING && !source->stopped) { int is_open; switch_file_handle_t *use_fh = &fh; switch_core_timer_next(&timer); olen = source->samples; if (source->chime_total) { if (source->chime_counter > 0) { source->chime_counter -= (int32_t)source->samples; } if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) { char *val; val = source->chime_list[source->chime_cur++]; if (source->chime_cur >= source->chime_total) { source->chime_cur = 0; } if (switch_core_file_open(&source->chime_fh, (char *) val, source->channels, source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val); } if (switch_core_file_has_video(&source->chime_fh)) { flush_video_queue(source->video_q); } } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: source->has_video = switch_core_file_has_video(use_fh) || source->cover_art || source->banner_txt; is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (source->hup) { source->hup = 0; if (is_open) { is_open = 0; switch_core_file_close(use_fh); flush_video_queue(source->video_q); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; switch_core_file_close(&fh); use_fh = &fh; } goto retry; } } if (is_open) { if (switch_core_has_video() && switch_core_file_has_video(use_fh)) { switch_frame_t vid_frame = { 0 }; if (use_fh == &source->chime_fh && switch_core_file_has_video(&fh)) { if (switch_core_file_read_video(&fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { switch_img_free(&vid_frame.img); } } if (switch_core_file_read_video(use_fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { if (vid_frame.img) { int flush = 1; source->has_video = 1; if (source->total) { if (switch_queue_trypush(source->video_q, vid_frame.img) == SWITCH_STATUS_SUCCESS) { flush = 0; } } if (flush) { switch_img_free(&vid_frame.img); flush_video_queue(source->video_q); } } } } else { source->has_video = 0; } if (use_fh == &source->chime_fh) { olen = source->samples; switch_core_file_read(&fh, abuf, &olen); olen = source->samples; } if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); flush_video_queue(source->video_q); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; } else { is_open = 0; } } else { if (use_fh == &source->chime_fh && source->chime_max) { source->chime_max_counter += (int32_t)source->samples; if (source->chime_max_counter >= source->chime_max) { source->chime_max_counter = 0; switch_core_file_close(use_fh); flush_video_queue(source->video_q); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } if (source->total) { switch_buffer_write(audio_buffer, abuf, olen * 2 * source->channels); } else { switch_buffer_zero(audio_buffer); } } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) { void *pop; used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels); if (!source->total) { flush_video_queue(source->video_q); } else { uint32_t bused = 0; switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (source->has_video) { switch_set_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO); } else { switch_clear_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO); } if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer); if (bused > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", cp->func, cp->file, cp->line, bused, (long)source->samples); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, dist_buf, used); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) { switch_image_t *img = (switch_image_t *) pop; switch_image_t *imgcp = NULL; if (source->total == 1) { switch_queue_push(source->context_list->video_q, img); } else { if (source->context_list) { switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (cp->video_q) { imgcp = NULL; switch_img_copy(img, &imgcp); if (imgcp) { if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) { flush_video_queue(cp->video_q); } } } } switch_mutex_unlock(source->mutex); } switch_img_free(&img); } } } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(dir_count); } } switch_dir_close(source->dir_handle); source->dir_handle = NULL; if (source->full_reload) { if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name); if (source->part_reload) { switch_xml_t cfg, xml, directory, param; if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); } if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) { for (param = switch_xml_child(directory, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); if (!strcasecmp(var, "shuffle")) { source->shuffle = switch_true(val); } else if (!strcasecmp(var, "chime-freq")) { int tmp = atoi(val); if (tmp > 1) { source->chime_freq = tmp; } } else if (!strcasecmp(var, "chime-max")) { int tmp = atoi(val); if (tmp > 1) { source->chime_max = tmp; } } else if (!strcasecmp(var, "chime-list")) { char *list_dup = switch_core_strdup(source->pool, val); source->chime_total = switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0]))); } else if (!strcasecmp(var, "interval")) { int tmp = atoi(val); if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) { source->interval = tmp; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL); } } if (source->chime_max) { source->chime_max *= source->rate; } if (source->chime_total) { source->chime_counter = source->rate * source->chime_freq; } } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name); source->part_reload = 0; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name); launch_streams(source->name); goto done; } } } done: switch_safe_free(source->banner_txt); if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&fh); } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&source->chime_fh); } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->name); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_buffer_destroy(&audio_buffer); flush_video_queue(source->video_q); if (fd > -1) { close(fd); } if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); THREADS--; switch_mutex_unlock(globals.mutex); return NULL; }
static switch_status_t webm_file_open(switch_file_handle_t *handle, const char *path) { webm_file_context_t *context; char *ext; unsigned int flags = 0; const char *tmp = NULL; char *fmtp; if ((ext = strrchr((char *)path, '.')) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n"); return SWITCH_STATUS_GENERR; } ext++; if ((context = (webm_file_context_t *)switch_core_alloc(handle->memory_pool, sizeof(webm_file_context_t))) == 0) { return SWITCH_STATUS_MEMERR; } memset(context, 0, sizeof(webm_file_context_t)); context->offset = -100; if (handle->params && (tmp = switch_event_get_header(handle->params, "webmv2_video_offset"))) { context->offset = atoi(tmp); } switch_mutex_init(&context->mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); switch_core_timer_init(&context->timer, "soft", 1, 1000, context->pool); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "init timer\n"); if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE; if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) { flags |= SWITCH_FOPEN_READ; } else { flags |= SWITCH_FOPEN_TRUNCATE; } } if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { flags |= SWITCH_FOPEN_READ; } context->writer = new mkvmuxer::MkvWriter(); if (!context->writer->Open(path)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error opening file %s\n", path); return SWITCH_STATUS_GENERR; } context->segment = new mkvmuxer::Segment(); if (!context->segment || !context->segment->Init(context->writer)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error init segment\n"); return SWITCH_STATUS_GENERR; } // context->segment.set_mode(mkvmuxer::Segment::kLive); context->segment->set_mode(mkvmuxer::Segment::kFile); context->segment->OutputCues(true); mkvmuxer::SegmentInfo* const info = context->segment->GetSegmentInfo(); info->set_timecode_scale(1000000); info->set_muxing_app("FreeSWITCH"); info->set_writing_app(switch_version_full()); context->audio_track_id = context->segment->AddAudioTrack(handle->samplerate, handle->channels, 0); if (!context->audio_track_id) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add audio track!\n"); goto end; } context->audio = static_cast<mkvmuxer::AudioTrack*>(context->segment->GetTrackByNumber(context->audio_track_id)); context->audio->set_codec_id("A_" AUDIO_CODEC); switch_buffer_create_dynamic(&context->audio_buffer, 512, 512, 0); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sample rate: %d, channels: %d\n", handle->samplerate, handle->channels); handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->pos = 0; handle->private_info = context; context->pool = handle->memory_pool; // handle->flags |= SWITCH_FILE_NATIVE; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz %s\n", path, handle->samplerate, switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) ? " with VIDEO" : ""); fmtp = switch_core_sprintf(context->pool, "useinbandfec=1;minptime=20;ptime=20;samplerate=%d%s", handle->samplerate, handle->channels == 2 ? ",stereo=1" : ""); if (switch_core_codec_init(&context->audio_codec, AUDIO_CODEC, NULL, fmtp, handle->samplerate, 20,//ms handle->channels, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n"); goto end; } if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) { if (switch_core_codec_init(&context->video_codec, "VP8", NULL, NULL, 90000, 0,//ms 1, SWITCH_CODEC_FLAG_ENCODE, NULL, handle->memory_pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video Codec H264 Activation Success\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Video Codec H264 Activation Fail\n"); goto end; } } if (!strcmp(AUDIO_CODEC, "VORBIS")) { uint16_t size = 0; uint8_t *codec_private_data = NULL; switch_core_codec_control(&context->audio_codec, SCC_GET_CODEC_PRIVATE, SCCT_INT, (void *)&size, NULL, (void **)&codec_private_data); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "======codec_private_data size: %d data: %p\n", size, codec_private_data); context->audio->SetCodecPrivate(codec_private_data, size); } if (1) { // for better quality? int bw = 4096; switch_core_codec_control(&context->video_codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, (void *)&bw, NULL, NULL); } switch_buffer_create_dynamic(&context->buf, 512, 512, 1024000); return SWITCH_STATUS_SUCCESS; end: if (context->segment) delete context->segment; if (context->writer) delete context->writer; return SWITCH_STATUS_GENERR; }
static switch_status_t tone_stream_file_open(switch_file_handle_t *handle, const char *path) { switch_buffer_t *audio_buffer = NULL; teletone_generation_session_t ts; char *tonespec; int loops = 0; char *tmp; int fd = -1; char buf[1024] = ""; size_t len; memset(&ts, 0, sizeof(ts)); tonespec = switch_core_strdup(handle->memory_pool, path); switch_buffer_create_dynamic(&audio_buffer, 1024, 1024, 0); switch_assert(audio_buffer); if ((tmp = (char *)switch_stristr(";loops=", tonespec))) { *tmp = '\0'; tmp += 7; if (tmp) { loops = atoi(tmp); switch_buffer_set_loops(audio_buffer, loops); } } if (handle->params) { if ((tmp = switch_event_get_header(handle->params, "loops"))) { loops = atoi(tmp); switch_buffer_set_loops(audio_buffer, loops); } } if (!handle->samplerate) { handle->samplerate = 8000; } handle->channels = 1; teletone_init_session(&ts, 0, teletone_handler, audio_buffer); ts.rate = handle->samplerate; ts.channels = 1; if (!strncasecmp(tonespec, "path=", 5)) { tmp = tonespec + 5; if ((fd = open(tmp, O_RDONLY)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to open [%s]\n", tmp); return SWITCH_STATUS_FALSE; } while ((len = switch_fd_read_line(fd, buf, sizeof(buf)))) { teletone_run(&ts, buf); } close(fd); fd = -1; } else { teletone_run(&ts, tonespec); } teletone_destroy_session(&ts); handle->private_info = audio_buffer; return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { switch_io_event_hook_read_frame_t *ptr; switch_status_t status = SWITCH_STATUS_FALSE; int need_codec, perfect, do_bugs = 0, do_resample = 0, is_cng = 0; switch_codec_implementation_t codec_impl; unsigned int flag = 0; switch_assert(session != NULL); if (switch_mutex_trylock(session->codec_read_mutex) == SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(session->codec_read_mutex); } else { switch_cond_next(); *frame = &runtime.dummy_cng_frame; return SWITCH_STATUS_SUCCESS; } if (!(session->read_codec && session->read_codec->implementation && switch_core_codec_ready(session->read_codec))) { if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_get_state(session->channel) == CS_HIBERNATE) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s reading on a session with no media!\n", switch_channel_get_name(session->channel)); switch_cond_next(); *frame = &runtime.dummy_cng_frame; return SWITCH_STATUS_SUCCESS; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel)); switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); return SWITCH_STATUS_FALSE; } switch_mutex_lock(session->codec_read_mutex); if (!switch_core_codec_ready(session->read_codec)) { switch_mutex_unlock(session->codec_read_mutex); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel)); switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); *frame = &runtime.dummy_cng_frame; return SWITCH_STATUS_FALSE; } switch_mutex_lock(session->read_codec->mutex); top: if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { switch_ivr_dmachine_ping(session->dmachine, NULL); } if (switch_channel_down(session->channel) || !switch_core_codec_ready(session->read_codec)) { *frame = NULL; status = SWITCH_STATUS_FALSE; goto even_more_done; } status = SWITCH_STATUS_FALSE; need_codec = perfect = 0; *frame = NULL; if (session->read_codec && !session->track_id && session->track_duration) { if (session->read_frame_count == 0) { switch_event_t *event; session->read_frame_count = (session->read_impl.actual_samples_per_second / session->read_impl.samples_per_packet) * session->track_duration; switch_event_create(&event, SWITCH_EVENT_SESSION_HEARTBEAT); switch_channel_event_set_data(session->channel, event); switch_event_fire(&event); } else { session->read_frame_count--; } } if (switch_channel_test_flag(session->channel, CF_HOLD)) { switch_yield(session->read_impl.microseconds_per_packet); status = SWITCH_STATUS_BREAK; goto even_more_done; } if (session->endpoint_interface->io_routines->read_frame) { switch_mutex_unlock(session->read_codec->mutex); switch_mutex_unlock(session->codec_read_mutex); if ((status = session->endpoint_interface->io_routines->read_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) { for (ptr = session->event_hooks.read_frame; ptr; ptr = ptr->next) { if ((status = ptr->read_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) { break; } } } if (!SWITCH_READ_ACCEPTABLE(status) || !session->read_codec || !switch_core_codec_ready(session->read_codec)) { *frame = NULL; return SWITCH_STATUS_FALSE; } switch_mutex_lock(session->codec_read_mutex); if (!switch_core_codec_ready(session->read_codec)) { switch_mutex_unlock(session->codec_read_mutex); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no read codec.\n", switch_channel_get_name(session->channel)); switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); *frame = &runtime.dummy_cng_frame; return SWITCH_STATUS_FALSE; } switch_mutex_lock(session->read_codec->mutex); if (!switch_core_codec_ready(session->read_codec)) { *frame = NULL; status = SWITCH_STATUS_FALSE; goto even_more_done; } } if (status != SWITCH_STATUS_SUCCESS) { goto done; } if (!(*frame)) { goto done; } switch_assert(*frame != NULL); if (switch_test_flag(*frame, SFF_PROXY_PACKET)) { /* Fast PASS! */ status = SWITCH_STATUS_SUCCESS; goto done; } if (switch_test_flag(*frame, SFF_CNG)) { status = SWITCH_STATUS_SUCCESS; if (!session->bugs && !session->plc) { goto done; } is_cng = 1; } switch_assert((*frame)->codec != NULL); if (!(session->read_codec && (*frame)->codec && (*frame)->codec->implementation) && switch_core_codec_ready((*frame)->codec)) { status = SWITCH_STATUS_FALSE; goto done; } codec_impl = *(*frame)->codec->implementation; if (session->read_codec->implementation->impl_id != codec_impl.impl_id) { need_codec = TRUE; } if (codec_impl.actual_samples_per_second != session->read_impl.actual_samples_per_second) { do_resample = 1; } if (session->bugs && !need_codec) { do_bugs = 1; need_codec = 1; } if (switch_test_flag(session, SSF_READ_TRANSCODE) && !need_codec && switch_core_codec_ready(session->read_codec)) { switch_core_session_t *other_session; const char *uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_SIGNAL_BOND_VARIABLE); switch_clear_flag(session, SSF_READ_TRANSCODE); if (uuid && (other_session = switch_core_session_locate(uuid))) { switch_set_flag(other_session, SSF_READ_CODEC_RESET); switch_set_flag(other_session, SSF_READ_CODEC_RESET); switch_set_flag(other_session, SSF_WRITE_CODEC_RESET); switch_core_session_rwunlock(other_session); } } if (switch_test_flag(session, SSF_READ_CODEC_RESET)) { switch_core_codec_reset(session->read_codec); switch_clear_flag(session, SSF_READ_CODEC_RESET); } if (status == SWITCH_STATUS_SUCCESS && need_codec) { switch_frame_t *enc_frame, *read_frame = *frame; switch_set_flag(session, SSF_READ_TRANSCODE); if (!switch_test_flag(session, SSF_WARN_TRANSCODE)) { switch_core_session_message_t msg = { 0 }; msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY; switch_core_session_receive_message(session, &msg); switch_set_flag(session, SSF_WARN_TRANSCODE); } if (read_frame->codec || is_cng) { session->raw_read_frame.datalen = session->raw_read_frame.buflen; if (is_cng) { if (session->plc) { plc_fillin(session->plc, session->raw_read_frame.data, read_frame->codec->implementation->decoded_bytes_per_packet / 2); is_cng = 0; flag &= !SFF_CNG; } else { memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet); } session->raw_read_frame.timestamp = 0; session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); read_frame = &session->raw_read_frame; status = SWITCH_STATUS_SUCCESS; } else { switch_codec_t *use_codec = read_frame->codec; if (do_bugs) { switch_thread_rwlock_wrlock(session->bug_rwlock); if (!session->bugs) { do_bugs = 0; switch_thread_rwlock_unlock(session->bug_rwlock); goto done; } if (!switch_core_codec_ready(&session->bug_codec)) { switch_core_codec_copy(read_frame->codec, &session->bug_codec, NULL); } use_codec = &session->bug_codec; switch_thread_rwlock_unlock(session->bug_rwlock); switch_thread_rwlock_wrlock(session->bug_rwlock); if (!session->bugs) { do_bugs = 0; } switch_thread_rwlock_unlock(session->bug_rwlock); if (!do_bugs) goto done; } if (switch_test_flag(read_frame, SFF_PLC)) { session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen); status = SWITCH_STATUS_SUCCESS; } else { status = switch_core_codec_decode(use_codec, session->read_codec, read_frame->data, read_frame->datalen, session->read_impl.actual_samples_per_second, session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate, &read_frame->flags); } if (status == SWITCH_STATUS_SUCCESS) { if ((switch_channel_test_flag(session->channel, CF_JITTERBUFFER) || switch_channel_test_flag(session->channel, CF_CNG_PLC)) && !session->plc) { session->plc = plc_init(NULL); } if (session->plc) { if (switch_test_flag(read_frame, SFF_PLC)) { plc_fillin(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2); switch_clear_flag(read_frame, SFF_PLC); } else { plc_rx(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2); } } } } if (do_resample && ((status == SWITCH_STATUS_SUCCESS) || is_cng)) { status = SWITCH_STATUS_RESAMPLE; } switch (status) { case SWITCH_STATUS_RESAMPLE: if (!session->read_resampler) { switch_mutex_lock(session->resample_mutex); status = switch_resample_create(&session->read_resampler, read_frame->codec->implementation->actual_samples_per_second, session->read_impl.actual_samples_per_second, session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); switch_mutex_unlock(session->resample_mutex); if (status != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Unable to allocate resampler\n"); status = SWITCH_STATUS_FALSE; goto done; } } case SWITCH_STATUS_SUCCESS: session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); session->raw_read_frame.rate = read_frame->rate; if (read_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) { session->raw_read_frame.timestamp = 0; } else { session->raw_read_frame.timestamp = read_frame->timestamp; } session->raw_read_frame.ssrc = read_frame->ssrc; session->raw_read_frame.seq = read_frame->seq; session->raw_read_frame.m = read_frame->m; session->raw_read_frame.payload = read_frame->payload; session->raw_read_frame.flags = 0; if (switch_test_flag(read_frame, SFF_PLC)) { session->raw_read_frame.flags |= SFF_PLC; } read_frame = &session->raw_read_frame; break; case SWITCH_STATUS_NOOP: if (session->read_resampler) { switch_mutex_lock(session->resample_mutex); switch_resample_destroy(&session->read_resampler); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating read resampler\n"); switch_mutex_unlock(session->resample_mutex); } status = SWITCH_STATUS_SUCCESS; break; case SWITCH_STATUS_BREAK: memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet); session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); session->raw_read_frame.timestamp = read_frame->timestamp; session->raw_read_frame.rate = read_frame->rate; session->raw_read_frame.ssrc = read_frame->ssrc; session->raw_read_frame.seq = read_frame->seq; session->raw_read_frame.m = read_frame->m; session->raw_read_frame.payload = read_frame->payload; session->raw_read_frame.flags = 0; if (switch_test_flag(read_frame, SFF_PLC)) { session->raw_read_frame.flags |= SFF_PLC; } read_frame = &session->raw_read_frame; status = SWITCH_STATUS_SUCCESS; break; case SWITCH_STATUS_NOT_INITALIZED: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); goto done; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error!\n", session->read_codec->codec_interface->interface_name); goto done; } } if (session->bugs) { switch_media_bug_t *bp; switch_bool_t ok = SWITCH_TRUE; int prune = 0; switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { continue; } if (switch_test_flag(bp, SMBF_PRUNE)) { prune++; continue; } if (bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) { switch_mutex_lock(bp->read_mutex); switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen); if (bp->callback) { ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ); } switch_mutex_unlock(bp->read_mutex); } if (ok && switch_test_flag(bp, SMBF_READ_REPLACE)) { do_bugs = 0; if (bp->callback) { bp->read_replace_frame_in = read_frame; bp->read_replace_frame_out = read_frame; if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_REPLACE)) == SWITCH_TRUE) { read_frame = bp->read_replace_frame_out; } } } if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) { switch_set_flag(bp, SMBF_PRUNE); prune++; } } switch_thread_rwlock_unlock(session->bug_rwlock); if (prune) { switch_core_media_bug_prune(session); } } if (do_bugs) { goto done; } if (session->read_codec) { if (session->read_resampler) { short *data = read_frame->data; switch_mutex_lock(session->resample_mutex); switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2); memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); read_frame->samples = session->read_resampler->to_len; read_frame->datalen = session->read_resampler->to_len * 2; read_frame->rate = session->read_resampler->to_rate; switch_mutex_unlock(session->resample_mutex); } if (read_frame->datalen == session->read_impl.decoded_bytes_per_packet) { perfect = TRUE; } else { if (!session->raw_read_buffer) { switch_size_t bytes = session->read_impl.decoded_bytes_per_packet; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Engaging Read Buffer at %u bytes vs %u\n", (uint32_t) bytes, (uint32_t) (*frame)->datalen); switch_buffer_create_dynamic(&session->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, 0); } if (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen)) { status = SWITCH_STATUS_MEMERR; goto done; } } if (perfect || switch_buffer_inuse(session->raw_read_buffer) >= session->read_impl.decoded_bytes_per_packet) { if (perfect) { enc_frame = read_frame; session->raw_read_frame.rate = read_frame->rate; } else { session->raw_read_frame.datalen = (uint32_t) switch_buffer_read(session->raw_read_buffer, session->raw_read_frame.data, session->read_impl.decoded_bytes_per_packet); session->raw_read_frame.rate = session->read_impl.actual_samples_per_second; enc_frame = &session->raw_read_frame; } session->enc_read_frame.datalen = session->enc_read_frame.buflen; switch_assert(session->read_codec != NULL); switch_assert(enc_frame != NULL); switch_assert(enc_frame->data != NULL); status = switch_core_codec_encode(session->read_codec, enc_frame->codec, enc_frame->data, enc_frame->datalen, session->read_impl.actual_samples_per_second, session->enc_read_frame.data, &session->enc_read_frame.datalen, &session->enc_read_frame.rate, &flag); switch (status) { case SWITCH_STATUS_RESAMPLE: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 1\n"); case SWITCH_STATUS_SUCCESS: session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t); if (perfect) { if (enc_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) { session->enc_read_frame.timestamp = 0; } else { session->enc_read_frame.timestamp = read_frame->timestamp; } session->enc_read_frame.rate = read_frame->rate; session->enc_read_frame.ssrc = read_frame->ssrc; session->enc_read_frame.seq = read_frame->seq; session->enc_read_frame.m = read_frame->m; session->enc_read_frame.payload = session->read_impl.ianacode; } *frame = &session->enc_read_frame; break; case SWITCH_STATUS_NOOP: session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_packet; session->raw_read_frame.timestamp = read_frame->timestamp; session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode; session->raw_read_frame.m = read_frame->m; session->raw_read_frame.ssrc = read_frame->ssrc; session->raw_read_frame.seq = read_frame->seq; *frame = enc_frame; status = SWITCH_STATUS_SUCCESS; break; case SWITCH_STATUS_NOT_INITALIZED: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); *frame = NULL; status = SWITCH_STATUS_GENERR; break; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error!\n", session->read_codec->codec_interface->interface_name); *frame = NULL; status = SWITCH_STATUS_GENERR; break; } } else { goto top; } } } done: if (!(*frame)) { status = SWITCH_STATUS_FALSE; } else { if (flag & SFF_CNG) { switch_set_flag((*frame), SFF_CNG); } if (session->bugs) { switch_media_bug_t *bp; switch_bool_t ok = SWITCH_TRUE; int prune = 0; switch_thread_rwlock_rdlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { continue; } if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { continue; } if (switch_test_flag(bp, SMBF_PRUNE)) { prune++; continue; } if (bp->ready && switch_test_flag(bp, SMBF_READ_PING)) { switch_mutex_lock(bp->read_mutex); if (bp->callback) { if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_PING) == SWITCH_FALSE || (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) { ok = SWITCH_FALSE; } } switch_mutex_unlock(bp->read_mutex); } if (ok == SWITCH_FALSE) { switch_set_flag(bp, SMBF_PRUNE); prune++; } } switch_thread_rwlock_unlock(session->bug_rwlock); if (prune) { switch_core_media_bug_prune(session); } } } even_more_done: if (!*frame || !(*frame)->codec || !(*frame)->codec->implementation || !switch_core_codec_ready((*frame)->codec)) { *frame = &runtime.dummy_cng_frame; } switch_mutex_unlock(session->read_codec->mutex); switch_mutex_unlock(session->codec_read_mutex); return status; }
static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *path) { vlc_file_context_t *context; libvlc_event_manager_t *mp_event_manager, *m_event_manager; context = switch_core_alloc(handle->memory_pool, sizeof(*context)); context->pool = handle->memory_pool; context->path = switch_core_strdup(context->pool, path); switch_buffer_create_dynamic(&(context->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool); switch_thread_cond_create(&(context->started), context->pool); if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for reading\n", path); /* Determine if this is a url or a path */ /* TODO: Change this so that it tries local files first, and then if it fails try location. */ if(! strncmp(context->path, "http", 4)){ context->m = libvlc_media_new_location(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", context->path); } else if (! strncmp(context->path, "mms", 3)){ context->m = libvlc_media_new_path(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", context->path); } else if (! strncmp(context->path, "/", 1)){ context->m = libvlc_media_new_path(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", context->path); } else { context->m = libvlc_media_new_location(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", context->path); } if ( context->m == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for reading\n", path); return SWITCH_STATUS_GENERR; } context->playing = 0; context->err = 0; context->mp = libvlc_media_player_new_from_media(context->m); if (!handle->samplerate) { handle->samplerate = 16000; } context->samplerate = handle->samplerate; context->channels = handle->channels; libvlc_audio_set_format(context->mp, "S16N", context->samplerate, handle->channels); m_event_manager = libvlc_media_event_manager(context->m); libvlc_event_attach(m_event_manager, libvlc_MediaStateChanged, vlc_media_state_callback, (void *) context); mp_event_manager = libvlc_media_player_event_manager(context->mp); libvlc_event_attach(mp_event_manager, libvlc_MediaPlayerEncounteredError, vlc_mediaplayer_error_callback, (void *) context); libvlc_audio_set_callbacks(context->mp, vlc_auto_play_callback, NULL,NULL,NULL,NULL, (void *) context); libvlc_media_player_play(context->mp); } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { const char * opts[10] = { vlc_args, switch_mprintf("--sout=%s", path) }; int opts_count = 10; if ( !handle->samplerate) handle->samplerate = 16000; context->samplerate = handle->samplerate; opts[2] = switch_mprintf("--imem-get=%ld", vlc_imem_get_callback); opts[3] = switch_mprintf("--imem-release=%ld", vlc_imem_release_callback); opts[4] = switch_mprintf("--imem-cat=%d", 4); opts[5] = "--demux=rawaud"; opts[6] = "--rawaud-fourcc=s16l"; opts[7] = switch_mprintf("--rawaud-samplerate=%d", context->samplerate); opts[8] = switch_mprintf("--imem-data=%ld", context); //opts[9] = "--rawaud-channels=1"; /* Prepare to write to an output stream. */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path); /* load the vlc engine. */ context->inst_out = libvlc_new(opts_count, opts); /* Tell VLC the audio will come from memory, and to use the callbacks to fetch it. */ context->m = libvlc_media_new_location(context->inst_out, "imem/rawaud://"); context->mp = libvlc_media_player_new_from_media(context->m); context->samples = 0; context->pts = 0; context->playing = 1; libvlc_media_player_play(context->mp); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC tried to open %s for unknown reason\n", path); return SWITCH_STATUS_GENERR; } handle->private_info = context; return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session, const char *function, const char *target, switch_media_bug_callback_t callback, void *user_data, time_t stop_time, switch_media_bug_flag_t flags, switch_media_bug_t **new_bug) { switch_media_bug_t *bug, *bp; switch_size_t bytes; switch_event_t *event; int tap_only = 1, punt = 0; const char *p; if (!zstr(function)) { if ((flags & SMBF_ONE_ONLY)) { switch_thread_rwlock_wrlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { if (!zstr(bp->function) && !strcasecmp(function, bp->function)) { punt = 1; break; } } switch_thread_rwlock_unlock(session->bug_rwlock); } } if (punt) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Only one bug of this type allowed!\n"); } if (!switch_channel_media_ready(session->channel)) { if (switch_channel_pre_answer(session->channel) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; } } *new_bug = NULL; if ((p = switch_channel_get_variable(session->channel, "media_bug_answer_req")) && switch_true(p)) { flags |= SMBF_ANSWER_REQ; } #if 0 if (flags & SMBF_WRITE_REPLACE) { switch_thread_rwlock_wrlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { if (switch_test_flag(bp, SMBF_WRITE_REPLACE)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Only one bug of this type allowed!\n"); switch_thread_rwlock_unlock(session->bug_rwlock); return SWITCH_STATUS_GENERR; } } switch_thread_rwlock_unlock(session->bug_rwlock); } if (flags & SMBF_READ_REPLACE) { switch_thread_rwlock_wrlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { if (switch_test_flag(bp, SMBF_READ_REPLACE)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Only one bug of this type allowed!\n"); switch_thread_rwlock_unlock(session->bug_rwlock); return SWITCH_STATUS_GENERR; } } switch_thread_rwlock_unlock(session->bug_rwlock); } #endif if (!(bug = switch_core_session_alloc(session, sizeof(*bug)))) { return SWITCH_STATUS_MEMERR; } bug->callback = callback; bug->user_data = user_data; bug->session = session; bug->flags = flags; bug->function = "N/A"; bug->target = "N/A"; switch_core_session_get_read_impl(session, &bug->read_impl); switch_core_session_get_write_impl(session, &bug->write_impl); if (function) { bug->function = switch_core_session_strdup(session, function); } if (target) { bug->target = switch_core_session_strdup(session, target); } bug->stop_time = stop_time; bytes = bug->read_impl.decoded_bytes_per_packet; if (!bug->flags) { bug->flags = (SMBF_READ_STREAM | SMBF_WRITE_STREAM); } if (switch_test_flag(bug, SMBF_READ_STREAM) || switch_test_flag(bug, SMBF_READ_PING)) { switch_buffer_create_dynamic(&bug->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, MAX_BUG_BUFFER); switch_mutex_init(&bug->read_mutex, SWITCH_MUTEX_NESTED, session->pool); } bytes = bug->write_impl.decoded_bytes_per_packet; if (switch_test_flag(bug, SMBF_WRITE_STREAM)) { switch_buffer_create_dynamic(&bug->raw_write_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, MAX_BUG_BUFFER); switch_mutex_init(&bug->write_mutex, SWITCH_MUTEX_NESTED, session->pool); } if ((bug->flags & SMBF_THREAD_LOCK)) { bug->thread_id = switch_thread_self(); } if (bug->callback) { switch_bool_t result = bug->callback(bug, bug->user_data, SWITCH_ABC_TYPE_INIT); if (result == SWITCH_FALSE) { switch_core_media_bug_destroy(bug); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error attaching BUG to %s\n", switch_channel_get_name(session->channel)); return SWITCH_STATUS_GENERR; } } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Attaching BUG to %s\n", switch_channel_get_name(session->channel)); bug->ready = 1; switch_thread_rwlock_wrlock(session->bug_rwlock); bug->next = session->bugs; session->bugs = bug; for(bp = session->bugs; bp; bp = bp->next) { if (bp->ready && !switch_test_flag(bp, SMBF_TAP_NATIVE_READ) && !switch_test_flag(bp, SMBF_TAP_NATIVE_WRITE)) { tap_only = 0; } } switch_thread_rwlock_unlock(session->bug_rwlock); *new_bug = bug; if (tap_only) { switch_set_flag(session, SSF_MEDIA_BUG_TAP_ONLY); } else { switch_clear_flag(session, SSF_MEDIA_BUG_TAP_ONLY); } if (switch_event_create(&event, SWITCH_EVENT_MEDIA_BUG_START) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Media-Bug-Function", "%s", bug->function); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Media-Bug-Target", "%s", bug->target); switch_channel_event_set_data(session->channel, event); switch_event_fire(&event); } return SWITCH_STATUS_SUCCESS; }
static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags) { cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral)); char srate[25]; if (!cepstral) { return SWITCH_STATUS_MEMERR; } if (switch_buffer_create_dynamic(&cepstral->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Buffer Failed!\n"); return SWITCH_STATUS_MEMERR; } switch_mutex_init(&cepstral->audio_lock, SWITCH_MUTEX_NESTED, sh->memory_pool); cepstral->params = swift_params_new(NULL); swift_params_set_string(cepstral->params, "audio/encoding", "pcm16"); switch_snprintf(srate, sizeof(srate), "%d", rate); swift_params_set_string(cepstral->params, "audio/sampling-rate", srate); /* Open a Swift Port through which to make TTS calls */ if (!(cepstral->port = swift_port_open(engine, cepstral->params))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Port.\n"); goto all_done; } if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name); voice_name = NULL; } if (zstr(voice_name)) { /* Find the first voice on the system */ if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n"); goto all_done; } /* Set the voice found by find_first_voice() as the port's current voice */ if (SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n"); goto all_done; } voice_name = (char *) swift_voice_get_attribute(cepstral->voice, "name"); } if (voice_name) { switch_copy_string(sh->voice, voice_name, sizeof(sh->voice)); } swift_port_set_callback(cepstral->port, &write_audio, SWIFT_EVENT_AUDIO, cepstral); sh->private_info = cepstral; return SWITCH_STATUS_SUCCESS; all_done: return SWITCH_STATUS_FALSE; }
static JSBool teletone_construct(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) { JSObject *session_obj; struct teletone_obj *tto = NULL; struct js_session *jss = NULL; switch_memory_pool_t *pool; char *timer_name = NULL; switch_codec_implementation_t read_impl = { 0 }; if (argc > 0) { if (JS_ValueToObject(cx, argv[0], &session_obj)) { if (!(jss = JS_GetPrivate(cx, session_obj))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Find Session [1]\n"); return JS_FALSE; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Find Session [2]\n"); return JS_FALSE; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Session Arg\n"); return JS_FALSE; } if (argc > 1) { timer_name = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); } switch_core_new_memory_pool(&pool); if (!(tto = switch_core_alloc(pool, sizeof(*tto)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error\n"); return JS_FALSE; } switch_core_session_get_read_impl(jss->session, &read_impl); if (switch_core_codec_init(&tto->codec, "L16", NULL, read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000, read_impl.number_of_channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activated\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activation Failed\n"); return JS_FALSE; } if (timer_name) { unsigned int ms = read_impl.microseconds_per_packet / 1000; if (switch_core_timer_init(&tto->timer_base, timer_name, ms, (read_impl.samples_per_second / 50) * read_impl.number_of_channels, pool) == SWITCH_STATUS_SUCCESS) { tto->timer = &tto->timer_base; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timer INIT Success %u\n", ms); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timer INIT Failed\n"); } } switch_buffer_create_dynamic(&tto->audio_buffer, JS_BLOCK_SIZE, JS_BUFFER_SIZE, 0); tto->pool = pool; tto->obj = obj; tto->cx = cx; tto->session = jss->session; teletone_init_session(&tto->ts, 0, teletone_handler, tto); JS_SetPrivate(cx, obj, tto); return JS_TRUE; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { local_stream_source_t *source = obj; switch_file_handle_t fh = { 0 }; local_stream_context_t *cp; char file_buf[128] = "", path_buf[512] = ""; switch_timer_t timer = { 0 }; int fd = -1; switch_buffer_t *audio_buffer; switch_byte_t *dist_buf; switch_size_t used; int skip = 0; switch_memory_pool_t *temp_pool = NULL; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); if (source->shuffle) { skip = do_rand(); } switch_thread_rwlock_create(&source->rwlock, source->pool); if (RUNNING) { switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->name, source); switch_mutex_unlock(globals.mutex); source->ready = 1; } while (RUNNING && !source->stopped) { const char *fname; if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool"); goto done; } if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location); goto done; } switch_yield(1000000); while (RUNNING && !source->stopped) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; if (fd > -1) { char *p; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) { *p = '\0'; } } else { close(fd); fd = -1; continue; } } else { if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { break; } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); if (switch_stristr(".loc", path_buf)) { if ((fd = open(path_buf, O_RDONLY)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); } continue; } } if (skip > 0) { skip--; continue; } fname = path_buf; fh.prebuf = source->prebuf; fh.pre_buffer_datalen = source->prebuf; if (switch_core_file_open(&fh, (char *) fname, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); switch_yield(1000000); continue; } if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); switch_dir_close(source->dir_handle); source->dir_handle = NULL; goto done; } while (RUNNING && !source->stopped) { int is_open; switch_file_handle_t *use_fh = &fh; switch_core_timer_next(&timer); olen = source->samples; if (source->chime_total) { if (source->chime_counter > 0) { source->chime_counter -= (int32_t)source->samples; } if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) { char *val; val = source->chime_list[source->chime_cur++]; if (source->chime_cur >= source->chime_total) { source->chime_cur = 0; } if (switch_core_file_open(&source->chime_fh, (char *) val, source->channels, source->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val); } } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (source->hup) { source->hup = 0; if (is_open) { is_open = 0; switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; //switch_core_file_close(&fh); } } } if (is_open) { if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } is_open = 0; } else { if (use_fh == &source->chime_fh && source->chime_max) { source->chime_max_counter += (int32_t)source->samples; if (source->chime_max_counter >= source->chime_max) { source->chime_max_counter = 0; switch_core_file_close(use_fh); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } switch_buffer_write(audio_buffer, abuf, olen * 2); } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { uint32_t bused = 0; switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer); if (bused > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", cp->func, cp->file, cp->line, bused, (long)source->samples); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, dist_buf, used); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(); } } switch_dir_close(source->dir_handle); source->dir_handle = NULL; if (source->full_reload) { if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name); if (source->part_reload) { switch_xml_t cfg, xml, directory, param; if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf); } if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) { for (param = switch_xml_child(directory, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); if (!strcasecmp(var, "shuffle")) { source->shuffle = switch_true(val); } else if (!strcasecmp(var, "chime-freq")) { int tmp = atoi(val); if (tmp > 1) { source->chime_freq = tmp; } } else if (!strcasecmp(var, "chime-max")) { int tmp = atoi(val); if (tmp > 1) { source->chime_max = tmp; } } else if (!strcasecmp(var, "chime-list")) { char *list_dup = switch_core_strdup(source->pool, val); source->chime_total = switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0]))); } else if (!strcasecmp(var, "interval")) { int tmp = atoi(val); if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) { source->interval = tmp; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL); } } if (source->chime_max) { source->chime_max *= source->rate; } if (source->chime_total) { source->chime_counter = source->rate * source->chime_freq; } } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name); source->part_reload = 0; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name); launch_streams(source->name); goto done; } } } done: if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&fh); } if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { switch_core_file_close(&source->chime_fh); } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->name); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_buffer_destroy(&audio_buffer); if (fd > -1) { close(fd); } if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); } switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); THREADS--; switch_mutex_unlock(globals.mutex); return NULL; }
/** * Read from file * @param handle * @param data * @param len * @return */ static switch_status_t fileman_file_read(switch_file_handle_t *handle, void *data, size_t *len) { struct fileman_file_context *context = (struct fileman_file_context *)handle->private_info; switch_file_handle_t *fh = &context->fh; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_size_t o_len = 0; /* anything called "_len" is measured in 2-byte samples */ if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) { return switch_core_file_read(fh, data, len); } //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "len = %"SWITCH_SIZE_T_FMT"\n", *len); if (*len > context->max_frame_len) { *len = context->max_frame_len; } for (;;) { int do_speed = 1; size_t read_bytes = 0; if (switch_test_flag(handle, SWITCH_FILE_PAUSE)) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read pause frame\n"); memset(context->abuf, 255, *len * 2); do_speed = 0; o_len = *len; } else if (fh->sp_audio_buffer && (context->eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (*len * 2)))) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read speed frame\n"); /* get next speed frame */ if (!(read_bytes = switch_buffer_read(fh->sp_audio_buffer, context->abuf, *len * 2))) { /* This is the reverse of what happens in switch_ivr_play_file... i think that implementation is wrong */ if (context->eof) { /* done with file */ status = SWITCH_STATUS_FALSE; goto done; } else { /* try again to fetch frame */ continue; } } /* pad short frame with silence */ if (read_bytes < *len * 2) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Padding speed frame %"SWITCH_SIZE_T_FMT" bytes\n", (context->frame_len * 2) - read_bytes); memset(context->abuf + read_bytes, 255, (*len * 2) - read_bytes); } o_len = *len; do_speed = 0; } else if (fh->audio_buffer && (context->eof || (switch_buffer_inuse(fh->audio_buffer) > (switch_size_t) (*len * 2)))) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) Read audio frame\n"); /* get next file frame */ if (!(read_bytes = switch_buffer_read(fh->audio_buffer, context->abuf, *len * 2))) { if (context->eof) { /* done with file */ status = SWITCH_STATUS_FALSE; goto done; } else { /* try again to fetch frame */ continue; } } //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) Read audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes); fh->offset_pos += read_bytes / 2; //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "(2) file pos = %i\n", fh->offset_pos); /* pad short frame with silence */ if (read_bytes < (*len * 2)) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Padding audio frame %"SWITCH_SIZE_T_FMT" bytes\n", (context->frame_len * 2) - read_bytes); memset(context->abuf + read_bytes, 255, (*len * 2) - read_bytes); } o_len = *len; } else { if (context->eof) { /* done with file */ status = SWITCH_STATUS_FALSE; goto done; } o_len = FILE_STARTBYTES / 2; if (switch_core_file_read(fh, context->abuf, &o_len) != SWITCH_STATUS_SUCCESS) { context->eof++; /* at end of file... need to clear buffers before giving up */ continue; } //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read file %"SWITCH_SIZE_T_FMT" bytes\n", o_len * 2); /* add file data to audio bufer */ read_bytes = switch_buffer_write(fh->audio_buffer, context->abuf, o_len * 2); //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Write audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes); read_bytes = switch_buffer_read(fh->audio_buffer, context->abuf, *len * 2); o_len = read_bytes / 2; fh->offset_pos += o_len; //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Read audio frame %"SWITCH_SIZE_T_FMT" bytes\n", read_bytes); //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "file pos = %i\n", fh->offset_pos); } if (o_len <= 0) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "o_len <= 0 (%"SWITCH_SIZE_T_FMT")\n", o_len); status = SWITCH_STATUS_FALSE; goto done; } /* limit speed... there is a .25 factor change in packet size relative to original packet size for each increment. Too many increments and we cause badness when (factor * speed * o_len) > o_len */ if (handle->speed > 2) { handle->speed = 2; } else if (handle->speed < -2) { handle->speed = -2; } if (switch_test_flag(fh, SWITCH_FILE_SEEK)) { /* file position has changed flush the buffer */ switch_buffer_zero(fh->audio_buffer); switch_clear_flag(fh, SWITCH_FILE_SEEK); } /* generate speed frames */ if (handle->speed && do_speed) { float factor = 0.25f * abs(handle->speed); switch_size_t new_len, supplement_len, step_len; short *bp = context->abuf; switch_size_t wrote_len = 0; //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Generate speed frame (%i)\n", handle->speed); supplement_len = (int) (factor * o_len); if (!supplement_len) { supplement_len = 1; } new_len = (handle->speed > 0) ? o_len - supplement_len : o_len + supplement_len; step_len = (handle->speed > 0) ? (new_len / supplement_len) : (o_len / supplement_len); if (!fh->sp_audio_buffer) { switch_buffer_create_dynamic(&fh->sp_audio_buffer, 1024, 1024, 0); } while ((wrote_len + step_len) < new_len) { switch_buffer_write(fh->sp_audio_buffer, bp, step_len * 2); wrote_len += step_len; bp += step_len; if (handle->speed > 0) { bp++; } else { float f; short s; f = (float) (*bp + *(bp + 1) + *(bp - 1)); f /= 3; s = (short) f; switch_buffer_write(fh->sp_audio_buffer, &s, 2); wrote_len++; } } if (wrote_len < new_len) { switch_size_t r_len = new_len - wrote_len; switch_buffer_write(fh->sp_audio_buffer, bp, r_len * 2); wrote_len += r_len; } continue; } /* adjust volume on frame */ if (handle->vol) { //switch_log_printf(SWITCH_CHANNEL_UUID_LOG(context->uuid), SWITCH_LOG_DEBUG, "Adjust volume to = %i\n", handle->vol); switch_change_sln_volume(context->abuf, *len, handle->vol); } break; } done: /* copy frame over to return to caller */ memcpy(data, context->abuf, *len * 2); handle->offset_pos = context->fh.offset_pos; return status; }
static switch_status_t local_stream_file_open(switch_file_handle_t *handle, const char *path) { local_stream_context_t *context; local_stream_source_t *source; char *alt_path = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; /* already buffering a step back, so always disable it */ handle->pre_buffer_datalen = 0; if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n"); return SWITCH_STATUS_FALSE; } switch_mutex_lock(globals.mutex); top: alt_path = switch_mprintf("%s/%d", path, handle->samplerate); if ((source = switch_core_hash_find(globals.source_hash, alt_path))) { path = alt_path; } else { source = switch_core_hash_find(globals.source_hash, path); } if (source) { if (switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) { source = NULL; } } else { if (!switch_stristr("default", alt_path) && !switch_stristr("default", path)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown source %s, trying 'default'\n", path); free(alt_path); path = "default"; goto top; } } switch_mutex_unlock(globals.mutex); if (!source) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path); status = SWITCH_STATUS_FALSE; goto end; } if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { status = SWITCH_STATUS_MEMERR; goto end; } handle->samples = 0; handle->samplerate = source->rate; handle->channels = source->channels; handle->format = 0; handle->sections = 0; handle->seekable = 0; handle->speed = 0; handle->private_info = context; handle->interval = source->interval; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening Stream [%s] %dhz\n", path, handle->samplerate); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); status = SWITCH_STATUS_MEMERR; goto end; } context->source = source; context->file = handle->file; context->func = handle->func; context->line = handle->line; context->handle = handle; switch_mutex_lock(source->mutex); context->next = source->context_list; source->context_list = context; source->total++; switch_mutex_unlock(source->mutex); end: switch_safe_free(alt_path); return status; }
static switch_status_t shout_file_open(switch_file_handle_t *handle, const char *path) { shout_context_t *context; char *host, *file; char *username, *password, *port; char *err = NULL; const char *mpg123err = NULL; int portno = 0; if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { return SWITCH_STATUS_MEMERR; } if (!handle->samplerate) { handle->samplerate = 8000; } context->memory_pool = handle->memory_pool; context->samplerate = handle->samplerate; context->handle = handle; switch_thread_rwlock_create(&(context->rwlock), context->memory_pool); switch_thread_rwlock_rdlock(context->rwlock); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->memory_pool); if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { if (switch_buffer_create_dynamic(&context->audio_buffer, TC_BUFFER_SIZE, TC_BUFFER_SIZE * 2, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); goto error; } context->mh = our_mpg123_new(NULL, NULL); if (mpg123_format_all(context->mh) != MPG123_OK) { MPGERROR(); } if (mpg123_param(context->mh, MPG123_FORCE_RATE, context->samplerate, 0) != MPG123_OK) { MPGERROR(); } if (handle->handler) { if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_SEEKBUFFER | MPG123_MONO_MIX, 0) != MPG123_OK) { MPGERROR(); } if (mpg123_open_feed(context->mh) != MPG123_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening mpg feed\n"); mpg123err = mpg123_strerror(context->mh); goto error; } context->stream_url = switch_core_sprintf(context->memory_pool, "http://%s", path); context->prebuf = handle->prebuf; launch_read_stream_thread(context); } else { handle->seekable = 1; if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_MONO_MIX, 0) != MPG123_OK) { MPGERROR(); } if (mpg123_open(context->mh, path) != MPG123_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path); mpg123err = mpg123_strerror(context->mh); goto error; } } } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Appending to MP3 not supported.\n"); } if (!(context->gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto error; } if (!handle->handler) { id3tag_init(context->gfp); id3tag_v2_only(context->gfp); id3tag_pad_v2(context->gfp); } context->channels = handle->channels; lame_set_brate(context->gfp, 16 * (handle->samplerate / 8000) * handle->channels); lame_set_num_channels(context->gfp, handle->channels); lame_set_in_samplerate(context->gfp, handle->samplerate); lame_set_out_samplerate(context->gfp, handle->samplerate); if (handle->channels == 2) { lame_set_mode(context->gfp, STEREO); } else { lame_set_mode(context->gfp, MONO); } lame_set_quality(context->gfp, 2); /* 2=high 5 = medium 7=low */ lame_set_errorf(context->gfp, log_error); lame_set_debugf(context->gfp, log_debug); lame_set_msgf(context->gfp, log_msg); if (handle->handler) { if (switch_buffer_create_dynamic(&context->audio_buffer, MY_BLOCK_SIZE, MY_BUF_LEN, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); goto error; } lame_set_bWriteVbrTag(context->gfp, 0); lame_mp3_tags_fid(context->gfp, NULL); username = switch_core_strdup(handle->memory_pool, path); if (!(password = strchr(username, ':'))) { err = "invalid url"; goto error; } *password++ = '\0'; if (!(host = strchr(password, '@'))) { err = "invalid url"; goto error; } *host++ = '\0'; if ((file = strchr(host, '/'))) { *file++ = '\0'; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL: %s\n", path); goto error; } if ((port = strchr(host, ':'))) { *port++ = '\0'; if (port) { portno = atoi(port); } } if (!portno) { portno = 8000; } if (!(context->shout = shout_new())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate shout_t\n"); goto error; } if (shout_set_host(context->shout, host) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting hostname: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_protocol(context->shout, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting protocol: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_port(context->shout, portno) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting port: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_password(context->shout, password) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting password: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_mount(context->shout, file) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting mount: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_user(context->shout, username) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting user: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_url(context->shout, "http://www.freeswitch.org") != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting name: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_description(context->shout, "FreeSWITCH mod_shout Broadcasting Module") != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting description: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_audio_info(context->shout, "bitrate", "24000") != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting bitrate: %s\n", shout_get_error(context->shout)); goto error; } if (shout_set_format(context->shout, SHOUT_FORMAT_MP3) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error setting format: %s\n", shout_get_error(context->shout)); goto error; } } else { /* lame being lame and all has FILE * coded into it's API for some functions so we gotta use it */ if (!(context->fp = fopen(path, "wb+"))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path); goto error; } } } handle->samples = 0; handle->format = 0; handle->sections = 0; handle->speed = 0; handle->private_info = context; switch_thread_rwlock_unlock(context->rwlock); return SWITCH_STATUS_SUCCESS; error: switch_thread_rwlock_unlock(context->rwlock); if (err) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: %s\n", err); } if (mpg123err) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error from mpg123: %s\n", mpg123err); } free_context(context); return SWITCH_STATUS_GENERR; }
bool WSClientParser::InitChannel(WSChannel* wsChannel) { switch_core_session_t *session = wsChannel->session; switch_channel_t* channel = switch_core_session_get_channel(wsChannel->session); // 初始化语音 wsChannel->read_frame.data = wsChannel->databuf; wsChannel->read_frame.buflen = sizeof(wsChannel->databuf); /* Initialize read & write codecs */ if (switch_core_codec_init( &wsChannel->read_codec, /* name */ "SPEEX", /* modname */ NULL, /* fmtp */ NULL, /* rate */ 16000, /* ms */ 20, /* channels */ 1, /* flags */ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, /* codec settings */ NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf( SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "WSClientParser::InitChannel( " "[Fail, Can't initialize read codec], " "this : %p, " "wsChannel : %p " ")\n", this, wsChannel ); return false; } if (switch_core_codec_init( &wsChannel->write_codec, /* name */ "SPEEX", /* modname */ NULL, /* fmtp */ NULL, /* rate */ 16000, /* ms */ 20, /* channels */ 1, /* flags */ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, /* codec settings */ NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf( SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "" "WSClientParser::InitChannel( " "[Fail, Can't initialize write codec], " "this : %p, " "wsChannel : %p " ")\n", this, wsChannel ); return false; } switch_core_session_set_read_codec(session, &wsChannel->read_codec); switch_core_session_set_write_codec(session, &wsChannel->write_codec); //static inline uint8_t rtmp_audio_codec(int channels, int bits, int rate, rtmp_audio_format_t format) { wsChannel->audio_codec = 0xB2; //rtmp_audio_codec(1, 16, 0 /* speex is always 8000 */, RTMP_AUDIO_SPEEX); // 初始化视频 switch_codec_settings_t codec_settings = {{ 0 }}; wsChannel->video_read_frame.data = wsChannel->video_databuf; wsChannel->video_read_frame.buflen = sizeof(wsChannel->video_databuf); /* Initialize video read & write codecs */ if (switch_core_codec_init( &wsChannel->video_read_codec, /* name */ "H264", /* modname */ NULL, /* fmtp */ NULL, /* rate */ 90000, /* ms */ 0, /* channels */ 1, /* flags */ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, /* codec settings */ NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS ) { switch_log_printf( SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "WSClientParser::InitChannel( " "[Fail, Can't initialize video read codec], " "this : %p, " "wsChannel : %p " ") \n", this, wsChannel ); return false; } codec_settings.video.bandwidth = switch_parse_bandwidth_string("1mb"); if (switch_core_codec_init( &wsChannel->video_write_codec, /* name */ "H264", /* modname */ NULL, /* fmtp */ NULL, /* rate */ 90000, /* ms */ 0, /* channels */ 1, /* flags */ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, /* codec settings */ &codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS ) { switch_log_printf( SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "WSClientParser::InitChannel( " "[Fail, Can't initialize write codec], " "this : %p, " "wsChannel : %p " ") \n", this, wsChannel ); return false; } switch_core_session_set_video_read_codec(session, &wsChannel->video_read_codec); switch_core_session_set_video_write_codec(session, &wsChannel->video_write_codec); switch_channel_set_flag(channel, CF_VIDEO); wsChannel->mparams.external_video_source = SWITCH_TRUE; switch_media_handle_create(&wsChannel->media_handle, session, &wsChannel->mparams); wsChannel->video_read_frame.packet = wsChannel->video_databuf; wsChannel->video_read_frame.data = wsChannel->video_databuf + 12; wsChannel->video_read_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12; switch_mutex_init(&wsChannel->video_readbuf_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_buffer_create_dynamic(&wsChannel->video_readbuf, 1024, 1024, 2048000); wsChannel->video_codec = 0xB2; return true; }