Skip to content
Snippets Groups Projects
abstract_jb.c 31.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			frame = &ast_null_frame;
    			break;
    		case AST_JB_IMPL_INTERP:
    
    				tmp.subclass.format = framedata->last_format;
    
    				/* example: 8000hz / (1000 / 20ms) = 160 samples */
    
    				tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval);
    
    				tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
    				tmp.offset = AST_FRIENDLY_OFFSET;
    				tmp.src  = "func_jitterbuffer interpolation";
    
    				ast_frfree(frame);
    
    				frame = ast_frdup(&tmp);
    				break;
    			}
    			/* else fall through */
    		case AST_JB_IMPL_NOFRAME:
    
    			ast_frfree(frame);
    
    			frame = &ast_null_frame;
    			break;
    		}
    	}
    
    	if (frame->frametype == AST_FRAME_CONTROL) {
    		switch(frame->subclass.integer) {
    
    		case AST_CONTROL_HOLD:
    		case AST_CONTROL_UNHOLD:
    		case AST_CONTROL_T38_PARAMETERS:
    
    		case AST_CONTROL_SRCUPDATE:
    		case AST_CONTROL_SRCCHANGE:
    			framedata->jb_impl->force_resync(framedata->jb_obj);
    			break;
    		default:
    			break;
    		}
    	}
    
    	return frame;
    }
    
    /* set defaults */
    static int jb_framedata_init(struct jb_framedata *framedata, struct ast_jb_conf *jb_conf)
    {
    	int jb_impl_type = DEFAULT_TYPE;
    	/* Initialize defaults */
    	framedata->timer_fd = -1;
    	memcpy(&framedata->jb_conf, jb_conf, sizeof(*jb_conf));
    
    	/* Figure out implementation type from the configuration implementation string */
    	if (!ast_strlen_zero(jb_conf->impl)) {
    		if (!strcasecmp(jb_conf->impl, "fixed")) {
    			jb_impl_type = AST_JB_FIXED;
    		} else if (!strcasecmp(jb_conf->impl, "adaptive")) {
    			jb_impl_type = AST_JB_ADAPTIVE;
    		} else {
    			ast_log(LOG_WARNING, "Unknown Jitterbuffer type %s. Failed to create jitterbuffer.\n", jb_conf->impl);
    			return -1;
    		}
    	}
    
    	if (!(framedata->jb_impl = ast_jb_get_impl(jb_impl_type))) {
    		return -1;
    	}
    
    	if (!(framedata->timer = ast_timer_open())) {
    		return -1;
    	}
    
    	framedata->timer_fd = ast_timer_fd(framedata->timer);
    	framedata->timer_interval = DEFAULT_TIMER_INTERVAL;
    	ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval);
    	framedata->start_tv = ast_tvnow();
    
    	framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf);
    	return 0;
    }
    
    
    void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing)
    {
    	struct jb_framedata *framedata;
    	struct ast_datastore *datastore = NULL;
    	struct ast_framehook_interface interface = {
    		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
    		.event_cb = hook_event_cb,
    		.destroy_cb = hook_destroy_cb,
    	};
    	int i = 0;
    
    	/* If disabled, strip any existing jitterbuffer and don't replace it. */
    	if (!strcasecmp(jb_conf->impl, "disabled")) {
    		int *id;
    		ast_channel_lock(chan);
    		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
    			id = datastore->data;
    			ast_framehook_detach(chan, *id);
    			ast_channel_datastore_remove(chan, datastore);
    
    			ast_datastore_free(datastore);
    
    		}
    		ast_channel_unlock(chan);
    		return;
    	}
    
    	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
    		return;
    	}
    
    	if (jb_framedata_init(framedata, jb_conf)) {
    		jb_framedata_destroy(framedata);
    		return;
    	}
    
    	interface.data = framedata;
    
    	ast_channel_lock(chan);
    	i = ast_framehook_attach(chan, &interface);
    	if (i >= 0) {
    		int *id;
    		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
    			/* There is already a jitterbuffer on the channel. */
    			if (prefer_existing) {
    				/* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */
    				ast_framehook_detach(chan, i);
    				ast_channel_unlock(chan);
    				return;
    			}
    			/* We prefer the new jitterbuffer, so strip the old one. */
    			id = datastore->data;
    			ast_framehook_detach(chan, *id);
    			ast_channel_datastore_remove(chan, datastore);
    
    			ast_datastore_free(datastore);
    
    		}
    
    		if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
    			ast_framehook_detach(chan, i);
    			ast_channel_unlock(chan);
    			return;
    		}
    
    		if (!(id = ast_calloc(1, sizeof(int)))) {
    			ast_datastore_free(datastore);
    			ast_framehook_detach(chan, i);
    			ast_channel_unlock(chan);
    			return;
    		}
    
    		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
    		datastore->data = id;
    		ast_channel_datastore_add(chan, datastore);
    
    		ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
    	} else {
    		jb_framedata_destroy(framedata);
    		framedata = NULL;
    	}
    	ast_channel_unlock(chan);
    }