freeswitch开发笔记2 流式录放音

需求:freeswitch放音和录音使用远程文件,不可再本地生成文件,不可挂载
1.前期思路 放音:在文件内存处将文件变成语音流并上传至freeswitch内存中
录音:使用远程写入文件的方式,重写写入函数

freeswitch模块mod_shout支持流式录放音
https://freeswitch.org/confluence/display/FREESWITCH/mod_shout
icecast流媒体服务器
修改一下配置 fileroot是自行修改代码后加的配置项,存储录音文件的路径
放音文件放在webroot下
0.0.0.0
/home/umg/icecast/log
/usr/local/share/icecast/web
/home/umg/icecastfile
/usr/local/share/icecast/admin

修改代码 source.c

.

	    //if (mountinfo && mountinfo->dumpfile) //huangzl
    {
        char *filename = source->dumpfilename;
        ice_config_t *config = config_get_config_unlocked ();
        source->dumpfilename = malloc(strlen(config->fileroot_dir) + strlen(source->mount)+1);
        sprintf(source->dumpfilename, "%s%s", config->fileroot_dir, source->mount);
        //source->dumpfilename = strdup (mountinfo->dumpfile);
        free (filename);
    }
    //else
    //    source->dumpfilename = NULL;

修改代码 cfgfile.c

.

else if (xmlStrcmp (node->name, XMLSTR("fileroot")) == 0) { //huangzl
            if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
                ICECAST_LOG_WARN("<fileroot> must not be empty.");
                continue;
            }
            if (configuration->fileroot_dir) xmlFree(configuration->fileroot_dir);
            configuration->fileroot_dir = temp;
            if(configuration->fileroot_dir[strlen(configuration->fileroot_dir)-1] == '/')
                configuration->fileroot_dir[strlen(configuration->fileroot_dir)-1] = 0;
        }

测试过程中出现4.4-5.4秒中间出现1秒左右空白音,尾部少3秒左右长度
使用版本是:freeswitch1.6.20 修改mod_shout.c

static void *SWITCH_THREAD_FUNC write_stream_thread(switch_thread_t *thread, void *obj)
{
    shout_context_t *context = (shout_context_t *) obj;
    switch_size_t audio_read = 0;

    switch_thread_rwlock_rdlock(context->rwlock);

    if (!context->lame_ready) {
        lame_init_params(context->gfp);
        lame_print_config(context->gfp);
        context->lame_ready = 1;
    }

    while (!(context->err && audio_read == 0)) {
        unsigned char mp3buf[20480] = "";
        int16_t audio[8192] = { 0 };
        int rlen = 0;
        long ret = 0;
        audio_read = 0;

        switch_mutex_lock(context->audio_mutex);
        if (context->audio_buffer) {
            audio_read = switch_buffer_read(context->audio_buffer, audio, sizeof(audio));
        } else {
            context->err++;
        }
        switch_mutex_unlock(context->audio_mutex);

        //error_check();

        if (!audio_read) {
            //audio_read = sizeof(audio);
            //memset(audio, 255, sizeof(audio));
            if(!context->err){
                switch_yield(100000);
            }
            continue;
        }

        if (context->channels == 2) {
            int16_t l[4800] = { 0 };
            int16_t r[4800] = { 0 };
            int j = 0;
            switch_size_t i;

            for (i = 0; i < audio_read / 4; i++) {
                l[i] = audio[j++];
                r[i] = audio[j++];
            }

            if ((rlen = lame_encode_buffer(context->gfp, l, r, (int)(audio_read / 4), mp3buf, sizeof(mp3buf))) < 0) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen);
                goto error;
            }
	} else if (context->channels == 1) {
            if ((rlen = lame_encode_buffer(context->gfp, (void *) audio, NULL, (int)(audio_read / sizeof(int16_t)), mp3buf, sizeof(mp3buf))) < 0) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen);
                goto error;
            }
    }

        if (rlen) {
            ret = shout_send(context->shout, mp3buf, rlen);
            if (ret != SHOUTERR_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Send error: %s\n", shout_get_error(context->shout));
                goto error;
            }
        } else {
            memset(mp3buf, 0, 128);
            ret = shout_send(context->shout, mp3buf, 128);
        }
                           } 
        if(!context->err){            
        	shout_sync(context->shout);
            switch_yield(100000);        }
    }           
            
  error:
    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Thread Done\n");
    switch_thread_rwlock_unlock(context->rwlock);
            
    return NULL;
}           

出现新问题 挂断事件需要4秒后才能产生

修改释放时的异步等待

static inline void free_context(shout_context_t *context)
{
.....................................

      if (context->shout) {
          if (context->gfp) {
              unsigned char mp3buffer[8192];
              int len;
              int16_t blank[2048] = { 0 }, *r = NULL;
              int framesize;

              if (context->channels == 2) {
                  r = blank;
              }
              len = lame_encode_buffer(context->gfp, blank, r, sizeof(blank) / 2, mp3buffer, sizeof(mp3buffer));

              if (len) {
                  ret = shout_send(context->shout, mp3buffer, len);
                  if (ret == SHOUTERR_SUCCESS) {
                      //shout_sync(context->shout);
                      switch_yield(10000);
                  }
              }

              framesize = lame_get_framesize(context->gfp);
              if ( framesize ) {
                  while ((len = lame_encode_flush(context->gfp, mp3buffer, sizeof(mp3buffer))) > 0) {
                      ret = shout_send(context->shout, mp3buffer, len);

                      if (ret != SHOUTERR_SUCCESS) {
                          break;
                      } else {
                          switch_yield(10000);
                          //shout_sync(context->shout);
                      }
                  }
              }
          }

          shout_close(context->shout);
          context->shout = NULL;
      }
  	.....................................
}

icecast的source链接并发限制只有个位数,故将icecast的接收和写文件部分单独提出,解开了并发限制,作为流式录音服务器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值