Changeset 277 for pjproject/trunk
- Timestamp:
- Mar 4, 2006 2:52:44 PM (19 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 4 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/build/pjmedia.dsp
r229 r277 134 134 # Begin Source File 135 135 136 SOURCE=..\src\pjmedia\resample.c 137 # End Source File 138 # Begin Source File 139 136 140 SOURCE=..\src\pjmedia\rtcp.c 137 141 # End Source File … … 214 218 # Begin Source File 215 219 220 SOURCE=..\include\pjmedia\resample.h 221 # End Source File 222 # Begin Source File 223 216 224 SOURCE=..\include\pjmedia\rtcp.h 217 225 # End Source File … … 257 265 # End Source File 258 266 # End Group 259 # Begin Group "PortAudio "267 # Begin Group "PortAudio Files" 260 268 261 269 # PROP Default_Filter "" … … 394 402 395 403 SOURCE=..\src\pjmedia\portaudio\portaudio.h 404 # End Source File 405 # End Group 406 # Begin Group "Resample Files" 407 408 # PROP Default_Filter "" 409 # Begin Source File 410 411 SOURCE=..\src\pjmedia\largefilter.h 412 # End Source File 413 # Begin Source File 414 415 SOURCE=..\src\pjmedia\smallfilter.h 396 416 # End Source File 397 417 # End Group -
pjproject/trunk/pjmedia/include/pjmedia/conference.h
r222 r277 46 46 pjmedia_port_op rx_setting; 47 47 pj_bool_t *listener; 48 unsigned clock_rate; 49 unsigned samples_per_frame; 48 50 } pjmedia_conf_port_info; 49 51 -
pjproject/trunk/pjmedia/src/pjmedia/conference.c
r246 r277 18 18 */ 19 19 #include <pjmedia/conference.h> 20 #include <pjmedia/silencedet.h>21 #include <pjmedia/stream.h>22 #include <pjmedia/sound.h>23 20 #include <pjmedia/errno.h> 24 21 #include <pjmedia/port.h> 22 #include <pjmedia/resample.h> 23 #include <pjmedia/silencedet.h> 24 #include <pjmedia/sound.h> 25 #include <pjmedia/stream.h> 25 26 #include <pj/assert.h> 26 27 #include <pj/log.h> … … 40 41 #define RX_BUF_COUNT 8 41 42 43 #define BYTES_PER_SAMPLE 2 44 42 45 /* 43 46 * DON'T GET CONFUSED!! … … 48 51 49 52 53 /** 54 * This is a port connected to conference bridge. 55 */ 50 56 struct conf_port 51 57 { … … 58 64 pjmedia_silence_det *vad; /**< VAD for this port. */ 59 65 60 /* Tx buffer contains the frame to be "transmitted" to this port 61 * (i.e. for put_frame()). 62 * We use dual buffer since the port may be accessed by two threads, 63 * and we don't want to use mutex for synchronization. 66 /* Shortcut for port info. */ 67 unsigned clock_rate; /**< Port's clock rate. */ 68 unsigned samples_per_frame; /**< Port's samples per frame. */ 69 70 /* Resample, for converting clock rate, if they're different. */ 71 pjmedia_resample *rx_resample; 72 pjmedia_resample *tx_resample; 73 74 /* RX buffer is temporary buffer to be used when there is mismatch 75 * between port's sample rate or ptime with conference's sample rate 76 * or ptime. When both sample rate and ptime of the port match the 77 * conference settings, this buffer will not be used. 78 * 79 * This buffer contains samples at port's clock rate. 80 * The size of this buffer is the sum between port's samples per frame 81 * and bridge's samples per frame. 64 82 */ 65 pj_int16_t *cur_tx_buf; /**< Buffer for put_frame(). */ 66 pj_int16_t *tx_buf1; /**< Buffer 1. */ 67 pj_int16_t *tx_buf2; /**< Buffer 2. */ 68 69 /* Rx buffers is a special buffer for sound device port (port 0). 70 * It's not used by other ports. 71 */ 72 int rx_write, rx_read; 73 pj_int16_t *rx_buf[RX_BUF_COUNT]; /**< Buffer */ 74 75 76 /* Sum buf is a temporary buffer used to calculate the average signal 83 pj_int16_t *rx_buf; /**< The RX buffer. */ 84 unsigned rx_buf_cap; /**< Max size, in samples */ 85 unsigned rx_buf_count; /**< # of samples in the buf. */ 86 87 /* Mix buf is a temporary buffer used to calculate the average signal 77 88 * received by this port from all other ports. 89 * 90 * This buffer contains samples at bridge's clock rate. 91 * The size of this buffer is equal to samples per frame of the bridge. 92 * 93 * Note that the samples here are unsigned 32bit. 78 94 */ 79 95 unsigned sources; /**< Number of sources. */ 80 pj_uint32_t *sum_buf; /**< Total sum of signal. */ 96 pj_uint32_t *mix_buf; /**< Total sum of signal. */ 97 98 /* Tx buffer is a temporary buffer to be used when there's mismatch 99 * between port's clock rate or ptime with conference's sample rate 100 * or ptime. When both sample rate and ptime of the port match the 101 * conference's settings, this buffer will not be used. 102 * 103 * This buffer contains samples at port's clock rate. 104 * The size of this buffer is the sum between port's samples per frame 105 * and bridge's samples per frame. 106 */ 107 pj_int16_t *tx_buf; /**< Tx buffer. */ 108 unsigned tx_buf_cap; /**< Max size, in samples. */ 109 unsigned tx_buf_count; /**< # of samples in the buffer. */ 110 111 /* Snd buffers is a special buffer for sound device port (port 0). 112 * It's not used by other ports. 113 * 114 * There are multiple numbers of this buffer, because we can not expect 115 * the mic and speaker thread to run equally after one another. In most 116 * systems, each thread will run multiple times before the other thread 117 * gains execution time. For example, in my system, mic thread is called 118 * three times, then speaker thread is called three times, and so on. 119 */ 120 int snd_write_pos, snd_read_pos; 121 pj_int16_t *snd_buf[RX_BUF_COUNT]; /**< Buffer */ 81 122 }; 82 123 … … 95 136 struct conf_port **ports; /**< Array of ports. */ 96 137 pj_uint16_t *uns_buf; /**< Buf for unsigned conversion */ 97 unsigned sampling_rate; /**< Sampling rate. */138 unsigned clock_rate; /**< Sampling rate. */ 98 139 unsigned samples_per_frame; /**< Samples per frame. */ 99 140 unsigned bits_per_sample; /**< Bits per sample. */ 100 pj_snd_stream_info snd_info; 141 pj_snd_stream_info snd_info; /**< Sound device parameter. */ 101 142 }; 102 143 … … 120 161 static pj_status_t create_conf_port( pj_pool_t *pool, 121 162 pjmedia_conf *conf, 163 pjmedia_port *port, 122 164 const pj_str_t *name, 123 165 struct conf_port **p_conf_port) … … 150 192 pjmedia_silence_det_set_adaptive(conf_port->vad, conf->samples_per_frame); 151 193 152 153 /* Create TX buffers. */ 154 conf_port->tx_buf1 = pj_pool_zalloc(pool, conf->samples_per_frame * 155 sizeof(conf_port->tx_buf1[0])); 156 PJ_ASSERT_RETURN(conf_port->tx_buf1, PJ_ENOMEM); 157 158 conf_port->tx_buf2 = pj_pool_zalloc(pool, conf->samples_per_frame * 159 sizeof(conf_port->tx_buf2[0])); 160 PJ_ASSERT_RETURN(conf_port->tx_buf2, PJ_ENOMEM); 161 162 /* Set initial TX buffer */ 163 conf_port->cur_tx_buf = conf_port->tx_buf1; 164 165 /* Create temporary buffer to calculate average signal received by 166 * this port. 194 /* Save some port's infos, for convenience. */ 195 if (port) { 196 conf_port->port = port; 197 conf_port->clock_rate = port->info.sample_rate; 198 conf_port->samples_per_frame = port->info.samples_per_frame; 199 } else { 200 conf_port->port = NULL; 201 conf_port->clock_rate = conf->clock_rate; 202 conf_port->samples_per_frame = conf->samples_per_frame; 203 } 204 205 /* If port's clock rate is different than conference's clock rate, 206 * create a resample sessions. 167 207 */ 168 conf_port->sum_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 169 sizeof(conf_port->sum_buf[0])); 170 171 208 if (conf_port->clock_rate != conf->clock_rate) { 209 210 double factor; 211 212 factor = 1.0 * conf_port->clock_rate / conf->clock_rate; 213 214 /* Create resample for rx buffer. */ 215 status = pjmedia_resample_create( pool, 216 PJ_TRUE, /* High quality */ 217 PJ_TRUE, /* Large filter */ 218 conf_port->clock_rate,/* Rate in */ 219 conf->clock_rate, /* Rate out */ 220 (unsigned)(conf->samples_per_frame * 221 factor), 222 &conf_port->rx_resample); 223 if (status != PJ_SUCCESS) 224 return status; 225 226 227 /* Create resample for tx buffer. */ 228 status = pjmedia_resample_create(pool, 229 PJ_TRUE, /* High quality */ 230 PJ_TRUE, /* Large filter */ 231 conf->clock_rate, /* Rate in */ 232 conf_port->clock_rate, /* Rate out */ 233 conf->samples_per_frame, 234 &conf_port->tx_resample); 235 if (status != PJ_SUCCESS) 236 return status; 237 } 238 239 /* 240 * Initialize rx and tx buffer, only when port's samples per frame or 241 * port's clock rate is different then the conference bridge settings. 242 */ 243 if (conf_port->clock_rate != conf->clock_rate || 244 conf_port->samples_per_frame != conf->samples_per_frame) 245 { 246 /* Create RX buffer. */ 247 conf_port->rx_buf_cap = (unsigned)(conf_port->samples_per_frame + 248 conf->samples_per_frame * 249 conf_port->clock_rate * 1.0 / 250 conf->clock_rate); 251 conf_port->rx_buf_count = 0; 252 conf_port->rx_buf = pj_pool_alloc(pool, conf_port->rx_buf_cap * 253 sizeof(conf_port->rx_buf[0])); 254 PJ_ASSERT_RETURN(conf_port->rx_buf, PJ_ENOMEM); 255 256 /* Create TX buffer. */ 257 conf_port->tx_buf_cap = conf_port->rx_buf_cap; 258 conf_port->tx_buf_count = 0; 259 conf_port->tx_buf = pj_pool_alloc(pool, conf_port->tx_buf_cap * 260 sizeof(conf_port->tx_buf[0])); 261 PJ_ASSERT_RETURN(conf_port->tx_buf, PJ_ENOMEM); 262 } 263 264 265 /* Create mix buffer. */ 266 conf_port->mix_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 267 sizeof(conf_port->mix_buf[0])); 268 PJ_ASSERT_RETURN(conf_port->mix_buf, PJ_ENOMEM); 269 172 270 173 271 /* Done */ … … 190 288 /* Init default sound device parameters. */ 191 289 pj_memset(&conf->snd_info, 0, sizeof(conf->snd_info)); 192 conf->snd_info.samples_per_sec = conf-> sampling_rate;290 conf->snd_info.samples_per_sec = conf->clock_rate; 193 291 conf->snd_info.bits_per_sample = conf->bits_per_sample; 194 292 conf->snd_info.samples_per_frame = conf->samples_per_frame; … … 199 297 200 298 /* Create port */ 201 status = create_conf_port(pool, conf, &name, &conf_port);299 status = create_conf_port(pool, conf, NULL, &name, &conf_port); 202 300 if (status != PJ_SUCCESS) 203 301 goto on_error; … … 205 303 /* Sound device has rx buffers. */ 206 304 for (i=0; i<RX_BUF_COUNT; ++i) { 207 conf_port-> rx_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame *208 sizeof(conf_port-> rx_buf[0][0]));209 if (conf_port-> rx_buf[i] == NULL) {305 conf_port->snd_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame * 306 sizeof(conf_port->snd_buf[0][0])); 307 if (conf_port->snd_buf[i] == NULL) { 210 308 status = PJ_ENOMEM; 211 309 goto on_error; 212 310 } 213 311 } 214 conf_port-> rx_write= 0;215 conf_port-> rx_read= 0;312 conf_port->snd_write_pos = 0; 313 conf_port->snd_read_pos = 0; 216 314 217 315 … … 233 331 PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, 234 332 unsigned max_ports, 235 unsigned sampling_rate,333 unsigned clock_rate, 236 334 unsigned samples_per_frame, 237 335 unsigned bits_per_sample, … … 241 339 pj_status_t status; 242 340 341 /* Can only accept 16bits per sample, for now.. */ 342 PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); 343 243 344 PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports", 244 345 max_ports)); … … 252 353 253 354 conf->max_ports = max_ports; 254 conf-> sampling_rate = sampling_rate;355 conf->clock_rate = clock_rate; 255 356 conf->samples_per_frame = samples_per_frame; 256 357 conf->bits_per_sample = bits_per_sample; … … 403 504 404 505 /* Create port structure. */ 405 status = create_conf_port(pool, conf, port_name, &conf_port);506 status = create_conf_port(pool, conf, strm_port, port_name, &conf_port); 406 507 if (status != PJ_SUCCESS) { 407 508 pj_mutex_unlock(conf->mutex); 408 509 return status; 409 510 } 410 411 /* Set the port */412 conf_port->port = strm_port;413 511 414 512 /* Put the port. */ … … 635 733 info->rx_setting = conf_port->rx_setting; 636 734 info->listener = conf_port->listeners; 735 info->clock_rate = conf_port->clock_rate; 736 info->samples_per_frame = conf_port->samples_per_frame; 637 737 638 738 return PJ_SUCCESS; … … 672 772 return (pj_int16_t)(uns - 32767); 673 773 } 774 775 /* Copy samples */ 776 PJ_INLINE(void) copy_samples(pj_int16_t *dst, 777 const pj_int16_t *src, 778 unsigned count) 779 { 780 unsigned i; 781 for (i=0; i<count; ++i) 782 dst[i] = src[i]; 783 } 784 785 /* Zero samples. */ 786 PJ_INLINE(void) zero_samples(pj_int16_t *buf, unsigned count) 787 { 788 unsigned i; 789 for (i=0; i<count; ++i) 790 buf[i] = 0; 791 } 792 793 794 /* 795 * Read from port. 796 */ 797 static pj_status_t read_port( pjmedia_conf *conf, 798 struct conf_port *cport, pj_int16_t *frame, 799 pj_size_t count, pjmedia_frame_type *type ) 800 { 801 802 pj_assert(count == conf->samples_per_frame); 803 804 /* If port's samples per frame and sampling rate matches conference 805 * bridge's settings, get the frame directly from the port. 806 */ 807 if (cport->rx_buf_cap == 0) { 808 pjmedia_frame f; 809 pj_status_t status; 810 811 f.buf = frame; 812 f.size = count * BYTES_PER_SAMPLE; 813 814 status = (cport->port->get_frame)(cport->port, &f); 815 816 *type = f.type; 817 818 return status; 819 820 } else { 821 822 /* 823 * If we don't have enough samples in rx_buf, read from the port 824 * first. Remember that rx_buf may be in different clock rate! 825 */ 826 while (cport->rx_buf_count < count * 1.0 * 827 cport->clock_rate / conf->clock_rate) { 828 829 pjmedia_frame f; 830 pj_status_t status; 831 832 f.buf = cport->rx_buf + cport->rx_buf_count; 833 f.size = cport->samples_per_frame * BYTES_PER_SAMPLE; 834 835 status = pjmedia_port_get_frame(cport->port, &f); 836 837 if (status != PJ_SUCCESS) { 838 /* Fatal error! */ 839 return status; 840 } 841 842 if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) { 843 zero_samples( cport->rx_buf + cport->rx_buf_count, 844 cport->samples_per_frame); 845 } 846 847 cport->rx_buf_count += cport->samples_per_frame; 848 849 pj_assert(cport->rx_buf_count <= cport->rx_buf_cap); 850 } 851 852 /* 853 * If port's clock_rate is different, resample. 854 * Otherwise just copy. 855 */ 856 if (cport->clock_rate != conf->clock_rate) { 857 858 unsigned src_count; 859 860 pjmedia_resample_run( cport->rx_resample,cport->rx_buf, frame); 861 862 src_count = (unsigned)(count * 1.0 * cport->clock_rate / 863 conf->clock_rate); 864 cport->rx_buf_count -= src_count; 865 if (cport->rx_buf_count) { 866 copy_samples(cport->rx_buf, cport->rx_buf+src_count, 867 cport->rx_buf_count); 868 } 869 870 } else { 871 872 copy_samples(frame, cport->rx_buf, count); 873 cport->rx_buf_count -= count; 874 if (cport->rx_buf_count) { 875 copy_samples(cport->rx_buf, cport->rx_buf+count, 876 cport->rx_buf_count); 877 } 878 } 879 } 880 881 return PJ_SUCCESS; 882 } 883 884 885 /* 886 * Write the mixed signal to the port. 887 */ 888 static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport, 889 pj_uint32_t timestamp) 890 { 891 pj_int16_t *buf; 892 unsigned j; 893 894 /* If port is muted or nobody is transmitting to this port, 895 * transmit NULL frame. 896 */ 897 if (cport->tx_setting == PJMEDIA_PORT_MUTE || cport->sources==0) { 898 899 pjmedia_frame frame; 900 901 frame.type = PJMEDIA_FRAME_TYPE_NONE; 902 frame.buf = NULL; 903 frame.size = 0; 904 905 if (cport->port) 906 pjmedia_port_put_frame(cport->port, &frame); 907 908 return PJ_SUCCESS; 909 910 } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) { 911 return PJ_SUCCESS; 912 } 913 914 /* If there are sources in the mix buffer, convert the mixed samples 915 * to the mixed samples itself. This is possible because mixed sample 916 * is 32bit. 917 */ 918 buf = (pj_int16_t*)cport->mix_buf; 919 for (j=0; j<conf->samples_per_frame; ++j) { 920 buf[j] = unsigned2pcm(cport->mix_buf[j] / cport->sources); 921 } 922 923 /* If port has the same clock_date and samples_per_frame settings as 924 * the conference bridge, transmit the frame as is. 925 */ 926 if (cport->clock_rate == conf->clock_rate && 927 cport->samples_per_frame == conf->samples_per_frame) 928 { 929 pjmedia_frame frame; 930 931 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 932 frame.buf = (pj_int16_t*)cport->mix_buf; 933 frame.size = conf->samples_per_frame * BYTES_PER_SAMPLE; 934 frame.timestamp.u64 = timestamp; 935 936 if (cport->port != NULL) 937 return pjmedia_port_put_frame(cport->port, &frame); 938 else 939 return PJ_SUCCESS; 940 } 941 942 /* If it has different clock_rate, must resample. */ 943 if (cport->clock_rate != conf->clock_rate) { 944 945 unsigned dst_count; 946 947 pjmedia_resample_run( cport->tx_resample, buf, 948 cport->tx_buf + cport->tx_buf_count ); 949 950 dst_count = (unsigned)(conf->samples_per_frame * 1.0 * 951 cport->clock_rate / conf->clock_rate); 952 cport->tx_buf_count += dst_count; 953 954 } else { 955 /* Same clock rate. 956 * Just copy the samples to tx_buffer. 957 */ 958 copy_samples( cport->tx_buf + cport->tx_buf_count, 959 buf, conf->samples_per_frame ); 960 cport->tx_buf_count += conf->samples_per_frame; 961 } 962 963 /* Transmit once we have enough frame in the tx_buf. */ 964 if (cport->tx_buf_count >= cport->samples_per_frame) { 965 966 pjmedia_frame frame; 967 968 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 969 frame.buf = cport->tx_buf; 970 frame.size = cport->samples_per_frame * BYTES_PER_SAMPLE; 971 frame.timestamp.u64 = timestamp; 972 973 if (cport->port) 974 return pjmedia_port_put_frame(cport->port, &frame); 975 else 976 return PJ_SUCCESS; 977 } 978 979 return PJ_SUCCESS; 980 } 981 674 982 675 983 /* … … 682 990 { 683 991 pjmedia_conf *conf = user_data; 684 pj_int16_t *output_buf = output;685 992 unsigned ci, cj, i, j; 686 993 … … 695 1002 for (i=0, ci=0; i<conf->max_ports && ci < conf->port_cnt; ++i) { 696 1003 struct conf_port *conf_port = conf->ports[i]; 697 pj_uint32_t * sum_buf;1004 pj_uint32_t *mix_buf; 698 1005 699 1006 /* Skip empty slot. */ … … 704 1011 705 1012 conf_port->sources = 0; 706 sum_buf = conf_port->sum_buf;1013 mix_buf = conf_port->mix_buf; 707 1014 708 1015 for (j=0; j<conf->samples_per_frame; ++j) 709 sum_buf[j] = 0;1016 mix_buf[j] = 0; 710 1017 } 711 1018 712 1019 /* Get frames from all ports, and "mix" the signal 713 * to sum_buf of all listeners of the port.1020 * to mix_buf of all listeners of the port. 714 1021 */ 715 1022 for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { … … 733 1040 */ 734 1041 if (i==0) { 735 pj_int16_t * rx_buf;736 737 if (conf_port-> rx_read == conf_port->rx_write) {738 conf_port-> rx_read=739 (conf_port-> rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) %1042 pj_int16_t *snd_buf; 1043 1044 if (conf_port->snd_read_pos == conf_port->snd_write_pos) { 1045 conf_port->snd_read_pos = 1046 (conf_port->snd_write_pos+RX_BUF_COUNT-RX_BUF_COUNT/2) % 740 1047 RX_BUF_COUNT; 741 1048 } … … 752 1059 } 753 1060 754 rx_buf = conf_port->rx_buf[conf_port->rx_read];1061 snd_buf = conf_port->snd_buf[conf_port->snd_read_pos]; 755 1062 for (j=0; j<conf->samples_per_frame; ++j) { 756 ((pj_int16_t*)output)[j] = rx_buf[j];1063 ((pj_int16_t*)output)[j] = snd_buf[j]; 757 1064 } 758 conf_port-> rx_read = (conf_port->rx_read+1) % RX_BUF_COUNT;1065 conf_port->snd_read_pos = (conf_port->snd_read_pos+1) % RX_BUF_COUNT; 759 1066 760 1067 } else { 761 pjmedia_frame frame; 762 763 pj_memset(&frame, 0, sizeof(frame)); 764 frame.buf = output; 765 frame.size = size; 766 pjmedia_port_get_frame(conf_port->port, &frame); 767 768 if (frame.type == PJMEDIA_FRAME_TYPE_NONE) 1068 1069 pj_status_t status; 1070 pjmedia_frame_type frame_type; 1071 1072 status = read_port(conf, conf_port, output, 1073 conf->samples_per_frame, &frame_type); 1074 1075 if (status != PJ_SUCCESS) { 1076 PJ_LOG(4,(THIS_FILE, "Port %.*s get_frame() returned %d. " 1077 "Port is now disabled", 1078 (int)conf_port->name.slen, 1079 conf_port->name.ptr, 1080 status)); 1081 conf_port->rx_setting = PJMEDIA_PORT_DISABLE; 769 1082 continue; 1083 } 770 1084 } 771 772 /* Skip (after receiving the frame) if this port is muted. */773 if (conf_port->rx_setting == PJMEDIA_PORT_MUTE)774 continue;775 1085 776 1086 /* Also skip if this port doesn't have listeners. */ … … 794 1104 { 795 1105 struct conf_port *listener = conf->ports[j]; 796 pj_uint32_t * sum_buf;1106 pj_uint32_t *mix_buf; 797 1107 unsigned k; 798 1108 … … 811 1121 812 1122 /* Mix the buffer */ 813 sum_buf = listener->sum_buf;1123 mix_buf = listener->mix_buf; 814 1124 for (k=0; k<conf->samples_per_frame; ++k) 815 sum_buf[k] += (conf->uns_buf[k] * level);1125 mix_buf[k] += (conf->uns_buf[k] * level); 816 1126 817 1127 listener->sources += level; … … 822 1132 for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { 823 1133 struct conf_port *conf_port = conf->ports[i]; 824 pjmedia_frame frame; 825 pj_int16_t *target_buf; 1134 pj_status_t status; 826 1135 827 1136 if (!conf_port) … … 830 1139 ++ci; 831 1140 832 if (conf_port->tx_setting == PJMEDIA_PORT_MUTE) { 833 frame.type = PJMEDIA_FRAME_TYPE_NONE; 834 frame.buf = NULL; 835 frame.size = 0; 836 837 if (conf_port->port) 838 pjmedia_port_put_frame(conf_port->port, &frame); 839 840 continue; 841 842 } else if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE) { 1141 status = write_port( conf, conf_port, timestamp); 1142 if (status != PJ_SUCCESS) { 1143 PJ_LOG(4,(THIS_FILE, "Port %.*s put_frame() returned %d. " 1144 "Port is now disabled", 1145 (int)conf_port->name.slen, 1146 conf_port->name.ptr, 1147 status)); 1148 conf_port->tx_setting = PJMEDIA_PORT_DISABLE; 843 1149 continue; 844 1150 } 845 846 target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1?847 conf_port->tx_buf2 : conf_port->tx_buf1);848 849 if (conf_port->sources) {850 for (j=0; j<conf->samples_per_frame; ++j) {851 target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] /852 conf_port->sources);853 }854 }855 856 /* Switch buffer. */857 conf_port->cur_tx_buf = target_buf;858 859 pj_memset(&frame, 0, sizeof(frame));860 if (conf_port->sources) {861 862 pj_bool_t is_silence = PJ_FALSE;863 864 /* Apply silence detection. */865 #if 0866 is_silence = pjmedia_silence_det_detect(conf_port->vad,867 target_buf,868 conf->samples_per_frame,869 NULL);870 #endif871 frame.type = is_silence ? PJMEDIA_FRAME_TYPE_NONE :872 PJMEDIA_FRAME_TYPE_AUDIO;873 874 } else875 frame.type = PJMEDIA_FRAME_TYPE_NONE;876 877 frame.buf = conf_port->cur_tx_buf;878 frame.size = conf->samples_per_frame * conf->bits_per_sample / 8;879 frame.timestamp.u64 = timestamp;880 881 if (conf_port->port)882 pjmedia_port_put_frame(conf_port->port, &frame);883 884 1151 } 885 1152 886 1153 /* Return sound playback frame. */ 887 1154 if (conf->ports[0]->sources) { 888 for (j=0; j<conf->samples_per_frame; ++j)889 output_buf[j] = conf->ports[0]->cur_tx_buf[j];1155 copy_samples( output, (pj_int16_t*)conf->ports[0]->mix_buf, 1156 conf->samples_per_frame); 890 1157 } else { 891 for (j=0; j<conf->samples_per_frame; ++j) 892 output_buf[j] = 0; 1158 zero_samples( output, conf->samples_per_frame ); 893 1159 } 894 1160 … … 909 1175 pjmedia_conf *conf = user_data; 910 1176 struct conf_port *snd_port = conf->ports[0]; 911 pj_int16_t *target_ rx_buf;1177 pj_int16_t *target_snd_buf; 912 1178 unsigned i; 913 1179 … … 932 1198 933 1199 /* Determine which rx_buffer to fill in */ 934 target_ rx_buf = snd_port->rx_buf[snd_port->rx_write];1200 target_snd_buf = snd_port->snd_buf[snd_port->snd_write_pos]; 935 1201 936 1202 /* Copy samples from audio device to target rx_buffer */ 937 1203 for (i=0; i<conf->samples_per_frame; ++i) { 938 target_ rx_buf[i] = ((pj_int16_t*)input)[i];1204 target_snd_buf[i] = ((pj_int16_t*)input)[i]; 939 1205 } 940 1206 941 1207 /* Switch buffer */ 942 snd_port->rx_write = (snd_port->rx_write+1)%RX_BUF_COUNT; 943 944 945 /* Time for all ports (except sound port) to transmit frames */ 946 /* 947 for (i=1; i<conf->max_ports; ++i) { 948 struct conf_port *conf_port = conf->ports[i]; 949 pjmedia_frame frame; 950 951 if (!conf_port) 952 continue; 953 954 } 955 */ 956 957 return PJ_SUCCESS; 958 } 959 1208 snd_port->snd_write_pos = (snd_port->snd_write_pos+1)%RX_BUF_COUNT; 1209 1210 1211 return PJ_SUCCESS; 1212 } 1213 -
pjproject/trunk/pjmedia/src/pjmedia/file_port.c
r241 r277 28 28 29 29 #define SIGNATURE ('F'<<24|'I'<<16|'L'<<8|'E') 30 #define BUF_SIZE (320*10)31 30 32 31 struct file_port … … 60 59 port->base.info.pt = 0xFF; 61 60 port->base.info.encoding_name = pj_str("pcm"); 61 62 port->base.put_frame = &file_put_frame; 63 port->base.get_frame = &file_get_frame; 64 port->base.on_destroy = &file_on_destroy; 65 66 67 /* Put in default values. 68 * These will be overriden once the file is read. 69 */ 62 70 port->base.info.sample_rate = 8000; 63 71 port->base.info.bits_per_sample = 16; 64 72 port->base.info.samples_per_frame = 160; 65 73 port->base.info.bytes_per_frame = 320; 66 67 port->base.put_frame = &file_put_frame;68 port->base.get_frame = &file_get_frame;69 port->base.on_destroy = &file_on_destroy;70 74 71 75 return port; … … 137 141 if (wave_hdr.fmt_hdr.fmt_tag != 1 || 138 142 wave_hdr.fmt_hdr.nchan != 1 || 139 wave_hdr.fmt_hdr.sample_rate != 8000 || 140 wave_hdr.fmt_hdr.bytes_per_sec != 16000 || 141 wave_hdr.fmt_hdr.block_align != 2 || 142 wave_hdr.fmt_hdr.bits_per_sample != 16) 143 wave_hdr.fmt_hdr.bits_per_sample != 16 || 144 wave_hdr.fmt_hdr.block_align != 2) 143 145 { 144 146 pj_file_close(fd); … … 167 169 /* Initialize */ 168 170 file_port->base.user_data = user_data; 171 172 /* Update port info. */ 173 file_port->base.info.sample_rate = wave_hdr.fmt_hdr.sample_rate; 174 file_port->base.info.bits_per_sample = wave_hdr.fmt_hdr.bits_per_sample; 175 file_port->base.info.samples_per_frame = file_port->base.info.sample_rate * 176 20 / 1000; 177 file_port->base.info.bytes_per_frame = 178 file_port->base.info.samples_per_frame * 179 file_port->base.info.bits_per_sample / 8; 180 169 181 170 182 /* For this version, we only support reading the whole … … 223 235 { 224 236 struct file_port *port = (struct file_port*)this_port; 225 237 unsigned frame_size; 226 238 pj_assert(port->base.info.signature == SIGNATURE); 239 240 frame_size = port->base.info.bytes_per_frame; 227 241 228 242 /* Copy frame from buffer. */ 229 243 frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 230 frame->size = 320;244 frame->size = frame_size; 231 245 frame->timestamp.u64 = 0; 232 246 233 if (port->readpos + 320<= port->buf + port->bufsize) {234 pj_memcpy(frame->buf, port->readpos, 320);235 port->readpos += 320;247 if (port->readpos + frame_size <= port->buf + port->bufsize) { 248 pj_memcpy(frame->buf, port->readpos, frame_size); 249 port->readpos += frame_size; 236 250 if (port->readpos == port->buf + port->bufsize) 237 251 port->readpos = port->buf; … … 241 255 endread = (port->buf+port->bufsize) - port->readpos; 242 256 pj_memcpy(frame->buf, port->readpos, endread); 243 pj_memcpy(((char*)frame->buf)+endread, port->buf, 320-endread);244 port->readpos = port->buf + ( 320-endread);257 pj_memcpy(((char*)frame->buf)+endread, port->buf, frame_size-endread); 258 port->readpos = port->buf + (frame_size - endread); 245 259 } 246 260 … … 249 263 250 264 /* 251 * 265 * Destroy port. 252 266 */ 253 267 static pj_status_t file_on_destroy(pjmedia_port *this_port) -
pjproject/trunk/pjsip-apps/src/pjsua/main.c
r269 r277 385 385 } 386 386 } 387 printf("Port #%02d %20.*s transmitting to: %s\n",387 printf("Port #%02d[%2dKHz/%dms] %20.*s transmitting to: %s\n", 388 388 port_info->slot, 389 port_info->clock_rate/1000, 390 port_info->samples_per_frame * 1000 / port_info->clock_rate, 389 391 (int)port_info->name.slen, 390 392 port_info->name.ptr, -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r268 r277 178 178 int start_rtp_port;/**< Start of RTP port to try. */ 179 179 pjmedia_endpt *med_endpt; /**< Media endpoint. */ 180 unsigned clock_rate; /**< Internal clock rate. */ 180 181 pjmedia_conf *mconf; /**< Media conference. */ 181 182 pj_bool_t null_audio; /**< Null audio flag. */ -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r268 r277 73 73 pjsua.stun_port1 = pjsua.stun_port2 = 0; 74 74 75 /* Default: sampling rate is 8000 */ 76 pjsua.clock_rate = 8000; 77 75 78 /* Init accounts: */ 76 79 pjsua.acc_cnt = 1; … … 619 622 status = pjmedia_conf_create(pjsua.pool, 620 623 pjsua.max_calls+PJSUA_CONF_MORE_PORTS, 621 8000, 160, 16, &pjsua.mconf); 624 pjsua.clock_rate, 625 pjsua.clock_rate * 20 / 1000, 16, 626 &pjsua.mconf); 622 627 if (status != PJ_SUCCESS) { 623 628 pj_caching_pool_destroy(&pjsua.cp); -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c
r268 r277 84 84 puts(""); 85 85 puts("Media Options:"); 86 puts(" --wb Enable wideband codecs (16KHz)"); 87 puts(" --uwb Enable ultra-wideband codecs (32KHz)"); 86 88 puts(" --null-audio Use NULL audio device"); 87 89 puts(" --play-file=file Play WAV file in conference bridge"); … … 219 221 OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP, 220 222 OPT_AUTO_CONF, 221 OPT_PLAY_FILE, OPT_ RTP_PORT,223 OPT_PLAY_FILE, OPT_WB, OPT_UWB, OPT_RTP_PORT, 222 224 OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 223 225 }; … … 229 231 { "help", 0, 0, OPT_HELP}, 230 232 { "version", 0, 0, OPT_VERSION}, 233 { "wb", 0, 0, OPT_WB}, 234 { "uwb", 0, 0, OPT_UWB}, 231 235 { "null-audio", 0, 0, OPT_NULL_AUDIO}, 232 236 { "local-port", 1, 0, OPT_LOCAL_PORT}, … … 328 332 break; 329 333 334 case OPT_WB: 335 pjsua.clock_rate = 16000; 336 break; 337 338 case OPT_UWB: 339 pjsua.clock_rate = 32000; 340 break; 341 330 342 case OPT_LOCAL_PORT: /* local-port */ 331 343 lval = pj_strtoul(pj_cstr(&tmp, optarg));
Note: See TracChangeset
for help on using the changeset viewer.