diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/RtpStreamSender.java --- a/src/org/sipdroid/media/RtpStreamSender.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/media/RtpStreamSender.java Sat Jan 23 22:19:43 2010 +0100 @@ -19,42 +19,50 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package org.sipdroid.media; +package src.org.sipdroid.media; +import java.io.IOException; import java.io.InputStream; -import java.net.DatagramPacket; +import java.net.InetAddress; import java.util.Random; -import jlibrtp.RTPSession; -import jlibrtp.RtpPkt; +import org.sipdroid.sipua.UserAgent; +import org.sipdroid.sipua.ui.Receiver; +import org.sipdroid.sipua.ui.Settings; +import org.sipdroid.sipua.ui.Sipdroid; +import org.sipdroid.pjlib.Codec; -import org.sipdroid.media.codecs.Codec; +import src.org.sipdroid.net.RtpPacket; +import src.org.sipdroid.net.RtpSocket; +import src.org.sipdroid.net.SipdroidSocket; +import android.content.Context; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.MediaRecorder; +import android.preference.PreferenceManager; +import android.telephony.TelephonyManager; /** * RtpStreamSender is a generic stream sender. It takes an InputStream and sends * it through RTP. */ -public class RtpStreamSender extends Thread{ - - private static final boolean DEBUG = true; +public class RtpStreamSender extends Thread { + /** Whether working in debug mode. */ + public static boolean DEBUG = true; /** The RtpSocket */ - private RTPSession rtpSession = null; + RtpSocket rtp_socket = null; - /** Codec */ - private Codec codec; + /** Payload type */ + int p_type; - private int sampling_rate; + /** Number of frame per second */ + long frame_rate; /** Number of bytes per frame */ - private int frame_size; - - private int codec_frame_size; + int frame_size; /** * Whether it works synchronously with a local clock, or it it acts as slave @@ -62,33 +70,64 @@ */ boolean do_sync = true; + /** + * Synchronization correction value, in milliseconds. It accellarates the + * sending rate respect to the nominal value, in order to compensate program + * latencies. + */ int sync_adj = 0; /** Whether it is running */ boolean running = false; boolean muted = false; - private int codec_divider; - /** * Constructs a RtpStreamSender. * + * @param input_stream + * the stream to be sent + * @param do_sync + * whether time synchronization must be performed by the + * RtpStreamSender, or it is performed by the InputStream (e.g. + * the system audio input) + * @param payload_type + * the payload type + * @param frame_rate + * the frame rate, i.e. the number of frames that should be sent + * per second; it is used to calculate the nominal packet time + * and,in case of do_sync==true, the next departure time + * @param frame_size + * the size of the payload + * @param src_socket + * the socket used to send the RTP packet + * @param dest_addr + * the destination address + * @param dest_port + * the destination port */ - public RtpStreamSender(Codec co, RTPSession rtpSession) { - init(co, rtpSession); + public RtpStreamSender(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, int dest_port) { + init(do_sync, payload_type, frame_rate, frame_size, + src_socket, dest_addr, dest_port); } /** Inits the RtpStreamSender */ - private void init(Codec co, RTPSession rtpSession) { - this.rtpSession = rtpSession; - codec = co; - sampling_rate = codec.getInfo().samplingRate; - codec_frame_size = codec.getInfo().codecFrameSize; - codec_divider = codec.getInfo().rtpSampleDivider; - frame_size = 160 * codec_divider; - rtpSession.payloadType(codec.getInfo().rtpPayloadCode); - - this.do_sync = true; + private void init(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, + int dest_port) { + this.p_type = payload_type; + this.frame_rate = frame_rate; + this.frame_size = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("server","").equals("pbxes.org")? + (payload_type == 3?960:1024):frame_size; //15 + this.do_sync = do_sync; + try { + rtp_socket = new RtpSocket(src_socket, InetAddress + .getByName(dest_addr), dest_port); + } catch (Exception e) { + if (!Sipdroid.release) e.printStackTrace(); + } } /** Sets the synchronization adjustment time (in milliseconds). */ @@ -100,13 +139,13 @@ public boolean isRunning() { return running; } - + public boolean mute() { return muted = !muted; } public static int delay = 0; - + /** Stops running */ public void halt() { running = false; @@ -115,11 +154,11 @@ Random random; double smin = 200,s; int nearend; - + void calc(short[] lin,int off,int len) { int i,j; double sm = 30000,r; - + for (i = 0; i < len; i += 5) { j = lin[i+off]; s = 0.03*Math.abs(j) + 0.97*s; @@ -140,6 +179,43 @@ smin = sm*r + smin*(1-r); } + void calc1(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + lin[i+off] = (short)(j>>1); + } + } + + void calc5(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 16350) + lin[i+off] = 16350<<1; + else if (j < -16350) + lin[i+off] = -16350<<1; + else + lin[i+off] = (short)(j<<1); + } + } + + void calc10(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 8150) + lin[i+off] = 8150<<2; + else if (j < -8150) + lin[i+off] = -8150<<2; + else + lin[i+off] = (short)(j<<2); + } + } + void noise(short[] lin,int off,int len,double power) { int i,r = (int)(power*2); short ran; @@ -153,21 +229,23 @@ lin[i+off+3] = ran; } } - + public static int m; - + /** Runs it in a new Thread. */ public void run() { - if (rtpSession == null) + if (rtp_socket == null) return; - byte[] buffer = new byte[codec_frame_size + 12]; - DatagramPacket packet = new DatagramPacket(buffer, codec_frame_size + 12); - RtpPkt pkt = new RtpPkt(); - pkt.setRawPkt(buffer); - pkt.setPayloadType(codec.getInfo().rtpPayloadCode); + byte[] buffer = new byte[frame_size + 12]; + RtpPacket rtp_packet = new RtpPacket(buffer, 0); + rtp_packet.setPayloadType(p_type); int seqn = 0; long time = 0; double p = 0; + TelephonyManager tm = (TelephonyManager) Receiver.mContext.getSystemService(Context.TELEPHONY_SERVICE); + boolean improve = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("improve",false); + boolean useGSM = !PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("compression","edge").equals("never"); + int micgain = (int)(Settings.getMicGain()*10); running = true; m = 1; @@ -175,45 +253,127 @@ println("Reading blocks of " + buffer.length + " bytes"); android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); - - Codec.Context codecCtx = codec.initEncoder(); - - AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, - AudioRecord.getMinBufferSize(sampling_rate, + AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, + AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, - AudioFormat.ENCODING_PCM_16BIT)*2); - record.startRecording(); + AudioFormat.ENCODING_PCM_16BIT)*3/2); short[] lin = new short[frame_size*11]; int num,ring = 0; random = new Random(); + InputStream alerting = null; + try { + alerting = Receiver.mContext.getAssets().open("alerting"); + } catch (IOException e2) { + if (!Sipdroid.release) e2.printStackTrace(); + } + switch (p_type) { + case 3: + Codec.init(); + break; + case 0: + case 8: + G711.init(); + break; + } + record.startRecording(); while (running) { - num = record.read(lin,(ring+delay)%(frame_size*11),frame_size); - if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) { - calc(lin,(ring+delay)%(frame_size*11),num); - if (RtpStreamReceiver.nearend != 0) - noise(lin,(ring+delay)%(frame_size*11),num,p); - else if (nearend == 0) - p = 0.9*p + 0.1*s; - } - codec.encode(codecCtx, lin, ring%(frame_size*11), frame_size, buffer, 12); - ring += frame_size; - rtpSession.sendData(packet, pkt); - if (m == 2) { - rtpSession.sendData(packet, pkt); - println("retransmit"); - } - seqn++; - time += num; + if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD) { + record.stop(); + while (running && (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD)) { + try { + sleep(1000); + } catch (InterruptedException e1) { + } + } + record.startRecording(); + } + num = record.read(lin,(ring+delay)%(frame_size*11),frame_size); + + if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) { + calc(lin,(ring+delay)%(frame_size*11),num); + if (RtpStreamReceiver.nearend != 0) + noise(lin,(ring+delay)%(frame_size*11),num,p); + else if (nearend == 0) + p = 0.9*p + 0.1*s; + } else switch (micgain) { + case 1: + calc1(lin,(ring+delay)%(frame_size*11),num); + break; + case 5: + calc5(lin,(ring+delay)%(frame_size*11),num); + break; + case 10: + calc10(lin,(ring+delay)%(frame_size*11),num); + break; + } + if (Receiver.call_state != UserAgent.UA_STATE_INCALL && alerting != null) { + try { + if (alerting.available() < num) + alerting.reset(); + alerting.read(buffer,12,num); + } catch (IOException e) { + if (!Sipdroid.release) e.printStackTrace(); + } + switch (p_type) {// have to add ulaw case? + case 3: + G711.alaw2linear(buffer, lin, num); + num = Codec.encode(lin, 0, buffer, num); + break; + case 0: + G711.alaw2linear(buffer, lin, num); + G711.linear2ulaw(lin, 0, buffer, num); + break; + } + } else { + switch (p_type) { + case 3: + num = Codec.encode(lin, ring%(frame_size*11), buffer, num); + break; + case 0: + G711.linear2ulaw(lin, ring%(frame_size*11), buffer, num); + break; + case 8: + G711.linear2alaw(lin, ring%(frame_size*11), buffer, num); + break; + } + } + ring += frame_size; + rtp_packet.setSequenceNumber(seqn++); + rtp_packet.setTimestamp(time); + rtp_packet.setPayloadLength(num); + try { + rtp_socket.send(rtp_packet); + if (m == 2) + rtp_socket.send(rtp_packet); + } catch (IOException e) { + } + time += frame_size; + if (improve && RtpStreamReceiver.good != 0 && + RtpStreamReceiver.loss/RtpStreamReceiver.good > 0.01 && + (Receiver.on_wlan || tm.getNetworkType() != TelephonyManager.NETWORK_TYPE_EDGE)) + m = 2; + else + m = 1; + if (useGSM && p_type == 8 && !Receiver.on_wlan && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) { + rtp_packet.setPayloadType(p_type = 3); + if (frame_size == 1024) { + frame_size = 960; + ring = 0; + } + } } record.stop(); - rtpSession = null; - codec.cleanEncoder(codecCtx); + + rtp_socket.close(); + rtp_socket = null; + if (DEBUG) println("rtp sender terminated"); } /** Debug output */ private static void println(String str) { - android.util.Log.d("DEBUG","RtpStreamSender: " + str); + if (!Sipdroid.release) System.out.println("RtpStreamSender: " + str); } -} + +} \ No newline at end of file