胡斌

support build-in speex to aac,controled by the root config keyword: speex2aac on/off

  1 +[submodule "trunk/3rdparty/speex"]
  2 + path = trunk/3rdparty/speex
  3 + url = git@123.56.226.173:hubin/speex.git
  4 +[submodule "trunk/3rdparty/fdk-aac"]
  5 + path = trunk/3rdparty/fdk-aac
  6 + url = git@123.56.226.173:hubin/fdk-aac.git
fdk-aac @ db608fee
  1 +Subproject commit db608feeed80cb1e7d6db6818293fa24900d967a
speex @ 6da384f4
  1 +Subproject commit 6da384f4f06d8db9510937aa0206c340dcacc7a2
@@ -62,6 +62,9 @@ work_dir ./; @@ -62,6 +62,9 @@ work_dir ./;
62 # @reamrk do not support reload. 62 # @reamrk do not support reload.
63 # default: off 63 # default: off
64 asprocess off; 64 asprocess off;
  65 +# whether using build-in speex to aac transcoding
  66 +# default: off
  67 +speex2aac off;
65 68
66 ############################################################################################# 69 #############################################################################################
67 # heartbeat/stats sections 70 # heartbeat/stats sections
@@ -928,6 +931,16 @@ vhost same.vhost.forward.srs.com { @@ -928,6 +931,16 @@ vhost same.vhost.forward.srs.com {
928 # active-active for cdn to build high available fault tolerance system. 931 # active-active for cdn to build high available fault tolerance system.
929 # format: {ip}:{port} {ip_N}:{port_N} 932 # format: {ip}:{port} {ip_N}:{port_N}
930 forward 127.0.0.1:1936 127.0.0.1:1937; 933 forward 127.0.0.1:1936 127.0.0.1:1937;
  934 + # forward_in_turn all publish stream to the specified server in turn.
  935 + # this used to split/forward the current stream for transcode and make load balance
  936 + # active-active for cdn to build high available fault tolerance system.
  937 + # format: {ip}:{port} {ip_N}:{port_N}
  938 + forward_in_turn 127.0.0.1:19351 127.0.0.1:19352;
  939 + #if the forward server is same as this server , a origin,try use forward_peer,
  940 + #the stream pushed from other forward peer will not forward any more in this server
  941 + forward_peer 127.0.0.1:1936;
  942 + #list out the servers which is not srs ,used in forward or forward_in_turn,and forward_peer for example,forward to some CDN
  943 + forward_server_other 127.0.0.1:19351;
931 } 944 }
932 945
933 # the main comments for transcode 946 # the main comments for transcode
  1 +# main config for srs.
  2 +# @see full.conf for detail config.
  3 +
  4 +listen 1935;
  5 +max_connections 1000;
  6 +srs_log_tank file;
  7 +srs_log_file ./objs/srs.log;
  8 +speex2aac on;
  9 +vhost __defaultVhost__ {
  10 +}
1 -#!/bin/bash  
2 -  
3 ##################################################################################### 1 #####################################################################################
4 # the main output dir, all configure and make output are in this dir. 2 # the main output dir, all configure and make output are in this dir.
5 ##################################################################################### 3 #####################################################################################
@@ -125,6 +123,8 @@ if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = NO ]; then LibSSLRoot="${SRS @@ -125,6 +123,8 @@ if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = NO ]; then LibSSLRoot="${SRS
125 # gperftools-2.1, for mem check and mem/cpu profile 123 # gperftools-2.1, for mem check and mem/cpu profile
126 LibGperfRoot=""; LibGperfFile="" 124 LibGperfRoot=""; LibGperfFile=""
127 if [ $SRS_GPERF = YES ]; then LibGperfRoot="${SRS_OBJS_DIR}/gperf/include"; LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_and_profiler.a"; fi 125 if [ $SRS_GPERF = YES ]; then LibGperfRoot="${SRS_OBJS_DIR}/gperf/include"; LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_and_profiler.a"; fi
  126 +# codec libs:speex fdk-aac for SPEEX2AAC
  127 +LibSpeex2aacRoot="${SRS_OBJS_DIR}/libs/include"; LibSpeex2aacfile="${SRS_OBJS_DIR}/libs/lib/libspeex.a ${SRS_OBJS_DIR}/libs/lib/libfdk-aac.a"
128 # the link options, always use static link 128 # the link options, always use static link
129 SrsLinkOptions="-ldl"; 129 SrsLinkOptions="-ldl";
130 if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = YES ]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi fi 130 if [ $SRS_SSL = YES ]; then if [ $SRS_USE_SYS_SSL = YES ]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi fi
@@ -166,10 +166,18 @@ MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" @@ -166,10 +166,18 @@ MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack"
166 PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh 166 PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh
167 PROTOCOL_OBJS="${MODULE_OBJS[@]}" 167 PROTOCOL_OBJS="${MODULE_OBJS[@]}"
168 # 168 #
  169 +#SPEEX2AAC speex to aac
  170 +MODULE_ID="SPEEX2AAC"
  171 +MODULE_DEPENDS=("CORE" "KERNEL")
  172 +ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSpeex2aacRoot})
  173 +MODULE_FILES=("srs_tc_adc_speex" "srs_tc_aec_aac" "srs_tc_common")
  174 +SPEEX2AAC_INCS="src/transcode"; MODULE_DIR=${SPEEX2AAC_INCS} . auto/modules.sh
  175 +SPEEX2AAC_OBJS="${MODULE_OBJS[@]}"
  176 +#
169 #App Module 177 #App Module
170 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then 178 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
171 MODULE_ID="APP" 179 MODULE_ID="APP"
172 - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") 180 + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SPEEX2AAC")
173 ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${SRS_OBJS_DIR}) 181 ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${SRS_OBJS_DIR})
174 MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" 182 MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source"
175 "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" 183 "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream"
@@ -202,8 +210,8 @@ LIBS_OBJS="${MODULE_OBJS[@]}" @@ -202,8 +210,8 @@ LIBS_OBJS="${MODULE_OBJS[@]}"
202 #Main Module 210 #Main Module
203 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then 211 if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
204 MODULE_ID="MAIN" 212 MODULE_ID="MAIN"
205 - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")  
206 - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot} ${LibSSLRoot}) 213 + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP" "SPEEX2AAC")
  214 + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibHttpParserRoot} ${LibSSLRoot} ${LibSpeex2aacRoot})
207 MODULE_FILES=("srs_main_server" "srs_main_ingest_hls") 215 MODULE_FILES=("srs_main_server" "srs_main_ingest_hls")
208 # add each modules for main 216 # add each modules for main
209 for SRS_MODULE in ${SRS_MODULES[*]}; do 217 for SRS_MODULE in ${SRS_MODULES[*]}; do
@@ -229,9 +237,9 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then @@ -229,9 +237,9 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
229 done 237 done
230 # 238 #
231 # all depends libraries 239 # all depends libraries
232 - ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibGperfFile}) 240 + ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibGperfFile} ${LibSpeex2aacfile})
233 # all depends objects 241 # all depends objects
234 - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}" 242 + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]} ${SPEEX2AAC_OBJS[@]}"
235 LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" 243 LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}"
236 # 244 #
237 # srs: srs(simple rtmp server) over st(state-threads) 245 # srs: srs(simple rtmp server) over st(state-threads)
@@ -258,10 +266,10 @@ if [ $SRS_UTEST = YES ]; then @@ -258,10 +266,10 @@ if [ $SRS_UTEST = YES ]; then
258 MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" 266 MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol"
259 "srs_utest_kernel" "srs_utest_core" "srs_utest_config" 267 "srs_utest_kernel" "srs_utest_core" "srs_utest_config"
260 "srs_utest_reload") 268 "srs_utest_reload")
261 - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})  
262 - ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile}) 269 + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSpeex2aacRoot})
  270 + ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile} ${LibSSLfile} ${LibSpeex2aacfile})
263 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP") 271 MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "APP")
264 - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]}" 272 + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${APP_OBJS[@]} ${SPEEX2AAC_OBJS[@]}"
265 LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh 273 LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh
266 fi 274 fi
267 275
@@ -349,6 +357,7 @@ else @@ -349,6 +357,7 @@ else
349 server: _prepare_dir 357 server: _prepare_dir
350 @echo "build the srs(simple rtmp server) over st(state-threads)" 358 @echo "build the srs(simple rtmp server) over st(state-threads)"
351 ./scripts/version.sh 359 ./scripts/version.sh
  360 + ./scripts/build_libs.sh
352 \$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} srs 361 \$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} srs
353 srs_ingest_hls: _prepare_dir 362 srs_ingest_hls: _prepare_dir
354 @echo "build the srs_ingest_hls for srs" 363 @echo "build the srs_ingest_hls for srs"
  1 +#!/bin/bash
  2 +mkdir -p objs
  3 +root=$PWD
  4 +if [ ! -d "$root/3rdparty/speex/.git" ]; then
  5 + cd ..
  6 + git submodule update --init
  7 + cd trunk
  8 +fi
  9 +if [ "$1" == "-f" ]; then
  10 + rm -rf objs/libs
  11 +fi
  12 +if [ ! -d "$root/objs/libs/include/speex" ]; then
  13 + cd 3rdparty/speex && ./autogen.sh && ./configure --prefix=$root/objs/libs --enable-shared=no && make && make install
  14 + cd $root
  15 +fi
  16 +if [ ! -d "$root/objs/libs/include/fdk-aac" ]; then
  17 + cd 3rdparty/fdk-aac && ./autogen.sh && ./configure --prefix=$root/objs/libs --enable-shared=no && make && make install
  18 +fi
  19 +
@@ -463,6 +463,8 @@ SrsConfig::SrsConfig() @@ -463,6 +463,8 @@ SrsConfig::SrsConfig()
463 root = new SrsConfDirective(); 463 root = new SrsConfDirective();
464 root->conf_line = 0; 464 root->conf_line = 0;
465 root->name = "root"; 465 root->name = "root";
  466 +
  467 + _speex2aac = false;
466 } 468 }
467 469
468 SrsConfig::~SrsConfig() 470 SrsConfig::~SrsConfig()
@@ -1005,6 +1007,8 @@ int SrsConfig::reload_conf(SrsConfig* conf) @@ -1005,6 +1007,8 @@ int SrsConfig::reload_conf(SrsConfig* conf)
1005 return ret; 1007 return ret;
1006 } 1008 }
1007 1009
  1010 + set_config_static();
  1011 +
1008 return ret; 1012 return ret;
1009 } 1013 }
1010 1014
@@ -1579,7 +1583,7 @@ int SrsConfig::check_config() @@ -1579,7 +1583,7 @@ int SrsConfig::check_config()
1579 && n != "max_connections" && n != "daemon" && n != "heartbeat" 1583 && n != "max_connections" && n != "daemon" && n != "heartbeat"
1580 && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" 1584 && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms"
1581 && n != "http_stream" && n != "http_server" && n != "stream_caster" 1585 && n != "http_stream" && n != "http_server" && n != "stream_caster"
1582 - && n != "utc_time" && n != "work_dir" && n != "asprocess" 1586 + && n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "speex2aac"
1583 ) { 1587 ) {
1584 ret = ERROR_SYSTEM_CONFIG_INVALID; 1588 ret = ERROR_SYSTEM_CONFIG_INVALID;
1585 srs_error("unsupported directive %s, ret=%d", n.c_str(), ret); 1589 srs_error("unsupported directive %s, ret=%d", n.c_str(), ret);
@@ -2080,9 +2084,27 @@ int SrsConfig::check_config() @@ -2080,9 +2084,27 @@ int SrsConfig::check_config()
2080 return ret; 2084 return ret;
2081 } 2085 }
2082 2086
  2087 +
  2088 + set_config_static();
  2089 +
2083 return ret; 2090 return ret;
2084 } 2091 }
2085 2092
  2093 +void SrsConfig::set_config_static()
  2094 +{
  2095 + SrsConfDirective* conf = root->get("speex2aac");
  2096 + if(conf){
  2097 + if(conf->arg0() == "on"){
  2098 + _speex2aac = true;
  2099 + }
  2100 + else
  2101 + _speex2aac = false;
  2102 + }
  2103 + else
  2104 + _speex2aac = false;
  2105 +
  2106 +}
  2107 +
2086 int SrsConfig::parse_buffer(SrsConfigBuffer* buffer) 2108 int SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
2087 { 2109 {
2088 int ret = ERROR_SUCCESS; 2110 int ret = ERROR_SUCCESS;
@@ -1141,6 +1141,18 @@ public: @@ -1141,6 +1141,18 @@ public:
1141 * @return the disk device name to stat. NULL if not configed. 1141 * @return the disk device name to stat. NULL if not configed.
1142 */ 1142 */
1143 virtual SrsConfDirective* get_stats_disk_device(); 1143 virtual SrsConfDirective* get_stats_disk_device();
  1144 +
  1145 +public:
  1146 +
  1147 + /**
  1148 + * the flag to indicate auto transcode with build-in modules
  1149 + */
  1150 + bool _speex2aac;
  1151 +private:
  1152 + /**
  1153 + * set the global static variables from config file
  1154 + */
  1155 + void set_config_static();
1144 }; 1156 };
1145 1157
1146 namespace _srs_internal 1158 namespace _srs_internal
@@ -46,6 +46,7 @@ using namespace std; @@ -46,6 +46,7 @@ using namespace std;
46 #include <srs_app_statistic.hpp> 46 #include <srs_app_statistic.hpp>
47 #include <srs_core_autofree.hpp> 47 #include <srs_core_autofree.hpp>
48 #include <srs_rtmp_utility.hpp> 48 #include <srs_rtmp_utility.hpp>
  49 +#include <srs_tc_av_codec.hpp>
49 50
50 #define CONST_MAX_JITTER_MS 250 51 #define CONST_MAX_JITTER_MS 250
51 #define CONST_MAX_JITTER_MS_NEG -250 52 #define CONST_MAX_JITTER_MS_NEG -250
@@ -970,6 +971,8 @@ SrsSource::SrsSource() @@ -970,6 +971,8 @@ SrsSource::SrsSource()
970 971
971 _srs_config->subscribe(this); 972 _srs_config->subscribe(this);
972 atc = false; 973 atc = false;
  974 + _speex_opt = NULL;
  975 + _aac_opt = NULL;
973 } 976 }
974 977
975 SrsSource::~SrsSource() 978 SrsSource::~SrsSource()
@@ -1013,6 +1016,15 @@ SrsSource::~SrsSource() @@ -1013,6 +1016,15 @@ SrsSource::~SrsSource()
1013 #endif 1016 #endif
1014 1017
1015 srs_freep(_req); 1018 srs_freep(_req);
  1019 +
  1020 + if (_speex_opt){
  1021 + adc_spx.close_codec((tc_audio_opt *)_speex_opt);
  1022 + _speex_opt = NULL;
  1023 + }
  1024 + if (_aac_opt) {
  1025 + aec_aac.close_codec((tc_audio_opt *)_aac_opt);
  1026 + _aac_opt = NULL;
  1027 + }
1016 } 1028 }
1017 1029
1018 void SrsSource::dispose() 1030 void SrsSource::dispose()
@@ -1662,6 +1674,101 @@ int SrsSource::on_data(SrsCommonMessage* shared_data) @@ -1662,6 +1674,101 @@ int SrsSource::on_data(SrsCommonMessage* shared_data)
1662 1674
1663 int SrsSource::on_audio(SrsCommonMessage* shared_audio) 1675 int SrsSource::on_audio(SrsCommonMessage* shared_audio)
1664 { 1676 {
  1677 + int ret = ERROR_SUCCESS;
  1678 +
  1679 + if(_srs_config->_speex2aac && SrsFlvCodec::audio_is_speex(shared_audio->payload, shared_audio->size)){
  1680 +
  1681 + if (NULL == _speex_opt){
  1682 + tc_audio_opt * speex_opt = new tc_audio_opt();
  1683 + _speex_opt = speex_opt;
  1684 + speex_opt->sample_rate = 16000;
  1685 + speex_opt->channels = 1;
  1686 + speex_opt->frame_size = 320;
  1687 + speex_opt->buffer_size = 640;
  1688 + adc_spx.open_codec(speex_opt);
  1689 + if (NULL == _aac_opt){
  1690 + tc_audio_opt * aac_opt = new tc_audio_opt();
  1691 + _aac_opt = aac_opt;
  1692 + aac_opt->sample_rate = 16000;
  1693 + aac_opt->channels = 1;
  1694 + aac_opt->frame_size = 1024;
  1695 + aac_opt->buffer_size = 2048;
  1696 + aac_opt->audio_bitrate = 64000;
  1697 +
  1698 + aec_aac.open_codec(aac_opt);
  1699 + char * buf = new char[aac_opt->extradata_size + 2];
  1700 + buf[0] = 0xAF;
  1701 + buf[1] = 0x00;
  1702 + memcpy(buf + 2, aac_opt->extradata, aac_opt->extradata_size);
  1703 + SrsCommonMessage msg;
  1704 + msg.header = shared_audio->header;
  1705 + msg.payload = buf;
  1706 + msg.size = aac_opt->extradata_size + 2;
  1707 + ret = _on_audio(&msg);
  1708 + freep(msg.payload);
  1709 + if(ret != ERROR_SUCCESS){
  1710 + freep(shared_audio->payload);
  1711 + return ret;
  1712 + }
  1713 + }
  1714 + }
  1715 + uint8_t* packet_data = (uint8_t *)shared_audio->payload + 1;
  1716 + int packet_size = shared_audio->size - 1;
  1717 +
  1718 + char * payload = shared_audio->payload;
  1719 +
  1720 + do {
  1721 + uint8_t out_data[1024];
  1722 + uint32_t out_size;
  1723 +
  1724 + int ret_spx = adc_spx.decode_frame((tc_audio_opt*)_speex_opt, packet_data, packet_size, out_data);
  1725 + if (ret_spx >= 0) {
  1726 +#if 0
  1727 + static FILE * fp = NULL;
  1728 + if (!fp){
  1729 + fp = fopen("testout.pcm", "wb");
  1730 + }
  1731 +
  1732 + if (fp){
  1733 + fwrite(out_data, 1, 640, fp);
  1734 + }
  1735 +#endif
  1736 + ((tc_audio_opt *)_aac_opt)->buffer_size = ((tc_audio_opt*)_speex_opt)->buffer_size;
  1737 +
  1738 + shared_audio->payload = new char[1024];
  1739 + out_size = 1022;
  1740 + int ret_aac = aec_aac.encode_frame((tc_audio_opt *)_aac_opt, out_data, (uint8_t *)shared_audio->payload + 2 , &out_size);
  1741 + if (ret_aac >= 0){
  1742 + if (out_size){
  1743 + shared_audio->payload[0] = 0xAF;
  1744 + shared_audio->payload[1] = 0x01;
  1745 + shared_audio->size = out_size +2;
  1746 + ret = _on_audio(shared_audio);
  1747 +#if 0
  1748 + static int max_out_size = 0;
  1749 + if(out_size > max_out_size){
  1750 + max_out_size = out_size;
  1751 + srs_trace("max_speex_aac_outsize:%d",max_out_size);
  1752 + }
  1753 +#endif
  1754 + }
  1755 + }
  1756 + }
  1757 + packet_data += ret_spx;
  1758 + packet_size -= ret_spx;
  1759 +
  1760 + } while (packet_size > 0);
  1761 +
  1762 + freep(payload);
  1763 + }
  1764 + else {
  1765 + return _on_audio(shared_audio);
  1766 + }
  1767 + return ret;
  1768 +}
  1769 +
  1770 +int SrsSource::_on_audio(SrsCommonMessage* shared_audio)
  1771 +{
1665 int ret = ERROR_SUCCESS; 1772 int ret = ERROR_SUCCESS;
1666 1773
1667 // monotically increase detect. 1774 // monotically increase detect.
@@ -511,6 +511,8 @@ private: @@ -511,6 +511,8 @@ private:
511 SrsSharedPtrMessage* cache_sh_video; 511 SrsSharedPtrMessage* cache_sh_video;
512 // the cached audio sequence header. 512 // the cached audio sequence header.
513 SrsSharedPtrMessage* cache_sh_audio; 513 SrsSharedPtrMessage* cache_sh_audio;
  514 + void * _speex_opt;
  515 + void * _aac_opt;
514 public: 516 public:
515 SrsSource(); 517 SrsSource();
516 virtual ~SrsSource(); 518 virtual ~SrsSource();
@@ -559,6 +561,7 @@ public: @@ -559,6 +561,7 @@ public:
559 public: 561 public:
560 virtual int on_audio(SrsCommonMessage* audio); 562 virtual int on_audio(SrsCommonMessage* audio);
561 private: 563 private:
  564 + virtual int _on_audio(SrsCommonMessage* audio);
562 virtual int on_audio_imp(SrsSharedPtrMessage* audio); 565 virtual int on_audio_imp(SrsSharedPtrMessage* audio);
563 public: 566 public:
564 virtual int on_video(SrsCommonMessage* video); 567 virtual int on_video(SrsCommonMessage* video);
@@ -266,6 +266,18 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size) @@ -266,6 +266,18 @@ bool SrsFlvCodec::audio_is_aac(char* data, int size)
266 return sound_format == SrsCodecAudioAAC; 266 return sound_format == SrsCodecAudioAAC;
267 } 267 }
268 268
  269 +bool SrsFlvCodec::audio_is_speex(char* data, int size)
  270 +{
  271 + // 1bytes required.
  272 + if (size < 1) {
  273 + return false;
  274 + }
  275 +
  276 + char sound_format = (*data >> 4) & 0x0F;
  277 +
  278 + return sound_format == SrsCodecAudioSpeex;
  279 +}
  280 +
269 bool SrsFlvCodec::video_is_acceptable(char* data, int size) 281 bool SrsFlvCodec::video_is_acceptable(char* data, int size)
270 { 282 {
271 // 1bytes required. 283 // 1bytes required.
@@ -223,6 +223,10 @@ public: @@ -223,6 +223,10 @@ public:
223 */ 223 */
224 static bool audio_is_aac(char* data, int size); 224 static bool audio_is_aac(char* data, int size);
225 /** 225 /**
  226 + * check codec speex.
  227 + */
  228 + static bool audio_is_speex(char* data, int size);
  229 + /**
226 * check the video RTMP/flv header info, 230 * check the video RTMP/flv header info,
227 * @return true if video RTMP/flv header is ok. 231 * @return true if video RTMP/flv header is ok.
228 * @remark all type of audio is possible, no need to check audio. 232 * @remark all type of audio is possible, no need to check audio.
  1 +#include "speex/speex.h"
  2 +#include "srs_tc_av_codec.hpp"
  3 +#include "srs_tc_common.hpp"
  4 +
  5 +
  6 +typedef struct {
  7 + SpeexBits bits;
  8 + void *dec_state;
  9 + int dec_frame_size;
  10 + int dec_buffer_size;
  11 + spx_int16_t* output_buffer;
  12 +} handle_adc_spx_t;
  13 +
  14 +
  15 +static int open_codec_spx(tc_audio_opt* opt) {
  16 + handle_adc_spx_t* s = (handle_adc_spx_t*)calloc(1, sizeof(handle_adc_spx_t));
  17 + opt->handle = s;
  18 + speex_bits_init(&s->bits);
  19 + s->dec_state = speex_decoder_init(&speex_wb_mode);
  20 + speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->dec_frame_size);
  21 + s->dec_buffer_size = s->dec_frame_size * sizeof(spx_int16_t);
  22 + opt->sample_rate = 16000;
  23 + opt->channels = 1;
  24 + opt->buffer_size = s->dec_buffer_size ;
  25 + opt->frame_size = s->dec_frame_size;
  26 + return 0;
  27 +}
  28 +
  29 +
  30 +static int decode_frame_spx(tc_audio_opt* opt, uint8_t* inData, uint32_t inDataSize, uint8_t* outData) {
  31 + handle_adc_spx_t* s = (handle_adc_spx_t*)opt->handle;
  32 + int consumed = 0;
  33 + if (speex_bits_remaining(&s->bits) < 5 ||
  34 + speex_bits_peek_unsigned(&s->bits, 5) == 0xF) {
  35 + speex_bits_read_from(&s->bits, (char*)inData, inDataSize);
  36 + consumed = inDataSize;
  37 + }
  38 +
  39 + int err = 0;
  40 + if ((err = speex_decode_int(s->dec_state, &s->bits, (spx_int16_t *)outData)) == 0) {
  41 + return consumed;
  42 + } else {
  43 + tc_log(LOG_LEVEL_ERROR, "speex_decode_int error: %d", err);
  44 + return -1;
  45 + }
  46 +}
  47 +
  48 +static int close_codec_spx(tc_audio_opt* opt) {
  49 + handle_adc_spx_t* s = (handle_adc_spx_t*)opt->handle;
  50 + speex_decoder_destroy(s->dec_state);
  51 + speex_bits_destroy(&s->bits);
  52 + return 0;
  53 +}
  54 +
  55 +
  56 +const tc_av_codec_t adc_spx = {
  57 + 11,
  58 + "adc_spx",
  59 + open_codec_spx,
  60 + decode_frame_spx,
  61 + NULL,
  62 + close_codec_spx
  63 +};
  1 +#include "fdk-aac/aacenc_lib.h"
  2 +#include "srs_tc_av_codec.hpp"
  3 +#include "srs_tc_common.hpp"
  4 +
  5 +static const char *aac_get_error(AACENC_ERROR err)
  6 +{
  7 + switch (err) {
  8 + case AACENC_OK:
  9 + return "No error";
  10 + case AACENC_INVALID_HANDLE:
  11 + return "Invalid handle";
  12 + case AACENC_MEMORY_ERROR:
  13 + return "Memory allocation error";
  14 + case AACENC_UNSUPPORTED_PARAMETER:
  15 + return "Unsupported parameter";
  16 + case AACENC_INVALID_CONFIG:
  17 + return "Invalid config";
  18 + case AACENC_INIT_ERROR:
  19 + return "Initialization error";
  20 + case AACENC_INIT_AAC_ERROR:
  21 + return "AAC library initialization error";
  22 + case AACENC_INIT_SBR_ERROR:
  23 + return "SBR library initialization error";
  24 + case AACENC_INIT_TP_ERROR:
  25 + return "Transport library initialization error";
  26 + case AACENC_INIT_META_ERROR:
  27 + return "Metadata library initialization error";
  28 + case AACENC_ENCODE_ERROR:
  29 + return "Encoding error";
  30 + case AACENC_ENCODE_EOF:
  31 + return "End of file";
  32 + default:
  33 + return "Unknown error";
  34 + }
  35 +}
  36 +
  37 +typedef struct {
  38 + HANDLE_AACENCODER handle;
  39 + int afterburner;
  40 + int eld_sbr;
  41 + int signaling;
  42 + int latm;
  43 + int header_period;
  44 + int vbr;
  45 + uint8_t buf[2048];
  46 + int data_len;
  47 +} handle_aec_aac_t;
  48 +
  49 +
  50 +static int open_codec_aac(tc_audio_opt* opt) {
  51 + handle_aec_aac_t* s = (handle_aec_aac_t*)calloc(1, sizeof(handle_aec_aac_t));
  52 + opt->handle = s;
  53 + AACENC_ERROR err = AACENC_OK;
  54 + AACENC_InfoStruct info = { 0 };
  55 + CHANNEL_MODE mode;
  56 + int sce = 0, cpe = 0;
  57 + do{
  58 + if ((err = aacEncOpen(&s->handle, 0, opt->channels)) != AACENC_OK) {
  59 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to open the encoder.\n");
  60 + break;
  61 + }
  62 +
  63 + int aot;
  64 + if(opt->audio_profile == 0) {
  65 + aot = 2; //LC-AAC
  66 + }else {
  67 + aot = 5; //HE-AAC
  68 + }
  69 +
  70 + //set audio object type
  71 + if ((err = aacEncoder_SetParam(s->handle, AACENC_AOT, aot)) != AACENC_OK) {
  72 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the AOT %d: %s\n",aot, aac_get_error(err));
  73 + break;
  74 + }
  75 +
  76 + //set sample rate
  77 + if ((err = aacEncoder_SetParam(s->handle, AACENC_SAMPLERATE, opt->sample_rate)) != AACENC_OK) {
  78 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the sample rate %d: %s\n",opt->sample_rate, aac_get_error(err));
  79 + break;
  80 + }
  81 +
  82 + switch (opt->channels) {
  83 + case 1: mode = MODE_1; sce = 1; cpe = 0; break;
  84 + case 2: mode = MODE_2; sce = 0; cpe = 1; break;
  85 + default:mode = MODE_1; sce = 1; cpe = 0; break;
  86 + }
  87 +
  88 + if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELMODE, mode)) != AACENC_OK) {
  89 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set channel mode %d: %s\n", mode, aac_get_error(err));
  90 + break;
  91 + }
  92 +
  93 + if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELORDER, 1)) != AACENC_OK) {
  94 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set channel order %d: %s\n", mode, aac_get_error(err));
  95 + break;
  96 + }
  97 +
  98 + if ((err = aacEncoder_SetParam(s->handle, AACENC_BITRATE, opt->audio_bitrate)) != AACENC_OK) {
  99 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to set the bitrate %d: %s\n", opt->audio_bitrate, aac_get_error(err));
  100 + break;
  101 + }
  102 + if (aacEncoder_SetParam(s->handle, AACENC_TRANSMUX, 0) != AACENC_OK) {
  103 + tc_log(LOG_LEVEL_ERROR, "Unable to set the ADTS transmux\n");
  104 + break;
  105 + }
  106 + if ((err = aacEncoder_SetParam(s->handle, AACENC_SIGNALING_MODE, 2)) != AACENC_OK) {
  107 + tc_log(LOG_LEVEL_ERROR, "Unable to set signaling mode %d: %s\n",2, aac_get_error(err));
  108 + break;
  109 + }
  110 +
  111 + if (aacEncEncode(s->handle, NULL, NULL, NULL, NULL) != AACENC_OK) {
  112 + tc_log(LOG_LEVEL_ERROR, "Unable to initialize the encoder\n");
  113 + return 1;
  114 + }
  115 + if (aacEncInfo(s->handle, &info) != AACENC_OK) {
  116 + tc_log(LOG_LEVEL_ERROR, "Unable to get the encoder info\n");
  117 + return 1;
  118 + }
  119 + opt->extradata = (uint8_t *)malloc(info.confSize);
  120 + opt->extradata_size = info.confSize;
  121 + memcpy(opt->extradata, info.confBuf, info.confSize);
  122 +
  123 + }while (0);
  124 +
  125 + if( err != AACENC_OK) {
  126 + aacEncClose(&s->handle);
  127 + }
  128 +
  129 + return 0;
  130 +}
  131 +
  132 +
  133 +static int encode_frame_aac(tc_audio_opt* opt, uint8_t* inData, uint8_t* inOutData, uint32_t* inOutDataSize) {
  134 + handle_aec_aac_t* s = (handle_aec_aac_t*)opt->handle;
  135 +
  136 + AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 };
  137 + AACENC_InArgs in_args = { 0 };
  138 + AACENC_OutArgs out_args = { 0 };
  139 + int in_identifier = IN_AUDIO_DATA;
  140 + int in_size, in_elem_size;
  141 + int out_identifier = OUT_BITSTREAM_DATA;
  142 + int out_size, out_elem_size;
  143 + void *in_ptr, *out_ptr;
  144 + AACENC_ERROR err;
  145 +
  146 + if (s->data_len + opt->buffer_size < 2048){
  147 + memcpy(s->buf + s->data_len, inData, opt->buffer_size);
  148 + s->data_len += opt->buffer_size;
  149 + *inOutDataSize = 0;
  150 + return 0;
  151 + }
  152 + else{
  153 + memcpy(s->buf + s->data_len, inData, 2048 - s->data_len);
  154 +
  155 + in_ptr = s->buf;
  156 + in_size = 2048;
  157 + in_elem_size = 2;
  158 +
  159 + in_args.numInSamples = opt->frame_size;
  160 + in_buf.numBufs = 1;
  161 + in_buf.bufs = &in_ptr;
  162 + in_buf.bufferIdentifiers = &in_identifier;
  163 + in_buf.bufSizes = &in_size;
  164 + in_buf.bufElSizes = &in_elem_size;
  165 +
  166 + out_ptr = inOutData;
  167 + out_size = *inOutDataSize;
  168 + out_elem_size = 1;
  169 + out_buf.numBufs = 1;
  170 + out_buf.bufs = &out_ptr;
  171 + out_buf.bufferIdentifiers = &out_identifier;
  172 + out_buf.bufSizes = &out_size;
  173 + out_buf.bufElSizes = &out_elem_size;
  174 +
  175 + if ((err = aacEncEncode(s->handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) {
  176 + tc_log(LOG_LEVEL_ERROR, "[aac] Unable to encode frame: %s\n", aac_get_error(err));
  177 + return -1;
  178 + }
  179 +
  180 + *inOutDataSize = out_args.numOutBytes;
  181 + memcpy(s->buf, inData + 2048 - s->data_len, opt->buffer_size -( 2048 - s->data_len));
  182 + s->data_len = opt->buffer_size - (2048 - s->data_len);
  183 + }
  184 +
  185 + return 0;
  186 +}
  187 +
  188 +static int close_codec_aac(tc_audio_opt* opt) {
  189 + handle_aec_aac_t* s = (handle_aec_aac_t*)opt->handle;
  190 + if (s->handle) {
  191 + aacEncClose(&s->handle);
  192 + }
  193 + freep(opt->extradata);
  194 + freep(opt->handle);
  195 + return 0;
  196 +}
  197 +
  198 +
  199 +const tc_av_codec_t aec_aac = {
  200 + 10,
  201 + "aec_aac",
  202 + open_codec_aac,
  203 + NULL,
  204 + encode_frame_aac,
  205 + close_codec_aac
  206 +};
  1 +#ifndef TC_AV_CODEC_H
  2 +#define TC_AV_CODEC_H
  3 +
  4 +#include <stdint.h>
  5 +#include <stdio.h>
  6 +#include <stdlib.h>
  7 +#include <string.h>
  8 +
  9 +#define MAX_EXTRA 3
  10 +
  11 +typedef void* handle_t;
  12 +
  13 +typedef struct {
  14 + int sample_rate;
  15 + int channels;
  16 + int frame_size;
  17 + int buffer_size;
  18 + int audio_profile;
  19 + int audio_bitrate;
  20 +
  21 + handle_t handle;
  22 +
  23 + uint32_t extradata_size;
  24 + uint8_t* extradata;
  25 +
  26 +}tc_audio_opt;
  27 +
  28 +typedef struct {
  29 + int codec_id;
  30 +
  31 + const char* codec_name;
  32 +
  33 + int (*open_codec)(tc_audio_opt* opt);
  34 +
  35 + int (*decode_frame)(tc_audio_opt* opt, uint8_t* inData, uint32_t inDataSize, uint8_t* outData);
  36 +
  37 + int (*encode_frame)(tc_audio_opt* opt, uint8_t* inData, uint8_t* inoutData, uint32_t* inoutDataSize);
  38 +
  39 + int (*close_codec)(tc_audio_opt* opt);
  40 +
  41 +}tc_av_codec_t;
  42 +
  43 +
  44 +extern const tc_av_codec_t adc_aac;
  45 +extern const tc_av_codec_t aec_aac;
  46 +
  47 +extern const tc_av_codec_t adc_spx;
  48 +
  49 +#define freep(x) if(x){ free(x); x = NULL;}
  50 +#endif /* tc_av_codec_h */
  1 +#include "srs_tc_common.hpp"
  2 +#include <stdarg.h>
  3 +#include <srs_kernel_log.hpp>
  4 +
  5 +void tc_log(int log_level, const char *format, ...)
  6 +{
  7 + va_list args;
  8 + va_start(args, format);
  9 +
  10 + if (log_level == LOG_LEVEL_INFO){
  11 + srs_info(format, args);
  12 + }
  13 + else if (log_level == LOG_LEVEL_WARN){
  14 + srs_warn(format, args);
  15 + }
  16 + else if (log_level == LOG_LEVEL_ERROR){
  17 + srs_error(format, args);
  18 + }
  19 +
  20 + va_end(args);
  21 +}
  1 +#ifndef TC_COMMON_H_
  2 +#define TC_COMMON_H_
  3 +
  4 +enum LOG_LEVEL
  5 +{
  6 + LOG_LEVEL_INFO,
  7 + LOG_LEVEL_WARN,
  8 + LOG_LEVEL_ERROR,
  9 +};
  10 +void tc_log(int log_level, const char *format, ...);
  11 +
  12 +#endif