src/org/sipdroid/media/RtpStreamSender.java
changeset 823 2036ebfaccda
child 830 c8b4ace735ea
equal deleted inserted replaced
536:537ddd8aa407 823:2036ebfaccda
       
     1 /*
       
     2  * Copyright (C) 2009 The Sipdroid Open Source Project
       
     3  * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
       
     4  * 
       
     5  * This file is part of Sipdroid (http://www.sipdroid.org)
       
     6  * 
       
     7  * Sipdroid is free software; you can redistribute it and/or modify
       
     8  * it under the terms of the GNU General Public License as published by
       
     9  * the Free Software Foundation; either version 3 of the License, or
       
    10  * (at your option) any later version.
       
    11  * 
       
    12  * This source code is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    15  * GNU General Public License for more details.
       
    16  * 
       
    17  * You should have received a copy of the GNU General Public License
       
    18  * along with this source code; if not, write to the Free Software
       
    19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    20  */
       
    21 
       
    22 package org.sipdroid.media;
       
    23 
       
    24 import java.io.InputStream;
       
    25 import java.net.DatagramPacket;
       
    26 import java.util.Random;
       
    27 
       
    28 import jlibrtp.RTPSession;
       
    29 import jlibrtp.RtpPkt;
       
    30 
       
    31 import org.sipdroid.media.codecs.Codec;
       
    32 
       
    33 import android.media.AudioFormat;
       
    34 import android.media.AudioManager;
       
    35 import android.media.AudioRecord;
       
    36 import android.media.MediaRecorder;
       
    37 
       
    38 /**
       
    39  * RtpStreamSender is a generic stream sender. It takes an InputStream and sends
       
    40  * it through RTP.
       
    41  */
       
    42 public class RtpStreamSender extends Thread{
       
    43 
       
    44 	private static final boolean DEBUG = true;
       
    45 
       
    46 	/** The RtpSocket */
       
    47 	//private RtpSocket rtp_socket = null;
       
    48 	private RTPSession rtpSession = null;
       
    49 
       
    50 	/** Codec */
       
    51 	private Codec codec;
       
    52 
       
    53 	private int sampling_rate;
       
    54 
       
    55 	/** Number of bytes per frame */
       
    56 	private int frame_size;
       
    57 
       
    58 	private int codec_frame_size;
       
    59 
       
    60 	/**
       
    61 	 * Whether it works synchronously with a local clock, or it it acts as slave
       
    62 	 * of the InputStream
       
    63 	 */
       
    64 	boolean do_sync = true;
       
    65 
       
    66 	int sync_adj = 0;
       
    67 
       
    68 	/** Whether it is running */
       
    69 	boolean running = false;
       
    70 	boolean muted = false;
       
    71 
       
    72 	private int codec_divider;
       
    73 
       
    74 	/**
       
    75 	 * Constructs a RtpStreamSender.
       
    76 	 * 
       
    77 	 */
       
    78 	public RtpStreamSender(Codec co, RTPSession rtpSession) {
       
    79 		init(co, rtpSession);
       
    80 	}
       
    81 
       
    82 	/** Inits the RtpStreamSender */
       
    83 	private void init(Codec co,	RTPSession rtpSession) {
       
    84 		this.rtpSession = rtpSession;
       
    85 		codec = co;
       
    86 		sampling_rate = codec.getInfo().samplingRate;
       
    87 		codec_frame_size = codec.getInfo().codecFrameSize;
       
    88 		codec_divider = codec.getInfo().rtpSampleDivider;
       
    89 		frame_size = 160 * codec_divider;
       
    90 		rtpSession.payloadType(codec.getInfo().rtpPayloadCode);
       
    91 
       
    92 		this.do_sync = true;
       
    93 	}
       
    94 
       
    95 	/** Sets the synchronization adjustment time (in milliseconds). */
       
    96 	public void setSyncAdj(int millisecs) {
       
    97 		sync_adj = millisecs;
       
    98 	}
       
    99 
       
   100 	/** Whether is running */
       
   101 	public boolean isRunning() {
       
   102 		return running;
       
   103 	}
       
   104 
       
   105 	public boolean mute() {
       
   106 		return muted = !muted;
       
   107 	}
       
   108 
       
   109 	public static int delay = 0;
       
   110 
       
   111 	/** Stops running */
       
   112 	public void halt() {
       
   113 		running = false;
       
   114 	}
       
   115 
       
   116 	Random random;
       
   117 	double smin = 200,s;
       
   118 	int nearend;
       
   119 
       
   120 	void calc(short[] lin,int off,int len) {
       
   121 		int i,j;
       
   122 		double sm = 30000,r;
       
   123 
       
   124 		for (i = 0; i < len; i += 5) {
       
   125 			j = lin[i+off];
       
   126 			s = 0.03*Math.abs(j) + 0.97*s;
       
   127 			if (s < sm) sm = s;
       
   128 			if (s > smin) nearend = 3000/5;
       
   129 			else if (nearend > 0) nearend--;
       
   130 		}
       
   131 		for (i = 0; i < len; i++) {
       
   132 			j = lin[i+off];
       
   133 			if (j > 6550)
       
   134 				lin[i+off] = 6550*5;
       
   135 			else if (j < -6550)
       
   136 				lin[i+off] = -6550*5;
       
   137 			else
       
   138 				lin[i+off] = (short)(j*5);
       
   139 		}
       
   140 		r = (double)len/100000;
       
   141 		smin = sm*r + smin*(1-r);
       
   142 	}
       
   143 
       
   144 	void noise(short[] lin,int off,int len,double power) {
       
   145 		int i,r = (int)(power*2);
       
   146 		short ran;
       
   147 
       
   148 		if (r == 0) r = 1;
       
   149 		for (i = 0; i < len; i += 4) {
       
   150 			ran = (short)(random.nextInt(r*2)-r);
       
   151 			lin[i+off] = ran;
       
   152 			lin[i+off+1] = ran;
       
   153 			lin[i+off+2] = ran;
       
   154 			lin[i+off+3] = ran;
       
   155 		}
       
   156 	}
       
   157 
       
   158 	public static int m;
       
   159 
       
   160 	/** Runs it in a new Thread. */
       
   161 	public void run() {
       
   162 		if (rtpSession == null)
       
   163 			return;
       
   164 		byte[] buffer = new byte[codec_frame_size + 12];
       
   165 		DatagramPacket packet = new DatagramPacket(buffer, codec_frame_size + 12);
       
   166 		RtpPkt pkt = new RtpPkt();
       
   167 		pkt.setRawPkt(buffer);
       
   168 		pkt.setPayloadType(codec.getInfo().rtpPayloadCode);
       
   169 		int seqn = 0;
       
   170 		long time = 0;
       
   171 		double p = 0;
       
   172 		running = true;
       
   173 		m = 1;
       
   174 
       
   175 		if (DEBUG)
       
   176 			println("Reading blocks of " + buffer.length + " bytes");
       
   177 
       
   178 		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
       
   179 
       
   180 		Codec.Context codecCtx = codec.initEncoder();
       
   181 
       
   182 		AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
       
   183 				AudioRecord.getMinBufferSize(sampling_rate, 
       
   184 						AudioFormat.CHANNEL_CONFIGURATION_MONO, 
       
   185 						AudioFormat.ENCODING_PCM_16BIT)*2);
       
   186 		record.startRecording();
       
   187 		short[] lin = new short[frame_size*11];
       
   188 		int num,ring = 0;
       
   189 		random = new Random();
       
   190 		while (running) {
       
   191 			num = record.read(lin,(ring+delay)%(frame_size*11),frame_size);
       
   192 			if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) {
       
   193 				calc(lin,(ring+delay)%(frame_size*11),num);
       
   194 				if (RtpStreamReceiver.nearend != 0)
       
   195 					noise(lin,(ring+delay)%(frame_size*11),num,p);
       
   196 				else if (nearend == 0)
       
   197 					p = 0.9*p + 0.1*s;
       
   198 			}
       
   199 			codec.encode(codecCtx, lin, ring%(frame_size*11), frame_size, buffer, 12);
       
   200 			ring += frame_size;
       
   201 			rtpSession.sendData(packet, pkt);
       
   202 			if (m == 2) {
       
   203 				rtpSession.sendData(packet, pkt);
       
   204 				println("retransmit");
       
   205 			}
       
   206 			seqn++;
       
   207 			time += num;
       
   208 		}
       
   209 		record.stop();
       
   210 		rtpSession = null;
       
   211 		codec.cleanEncoder(codecCtx);
       
   212 		if (DEBUG)
       
   213 			println("rtp sender terminated");
       
   214 	}
       
   215 
       
   216 	/** Debug output */
       
   217 	private static void println(String str) {
       
   218 		android.util.Log.d("DEBUG","RtpStreamSender: " + str);
       
   219 	}
       
   220 }