src/org/sipdroid/media/RtpStreamReceiver.java
changeset 839 0e5b95573614
parent 835 4e40f3481f23
child 1005 a2cad81f348b
equal deleted inserted replaced
822:696b2880c994 839:0e5b95573614
       
     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.IOException;
       
    25 import java.net.SocketException;
       
    26 
       
    27 import com.beem.project.beem.jingle.JingleService;
       
    28 import com.beem.project.beem.ui.Call;
       
    29 import org.sipdroid.net.RtpPacket;
       
    30 import org.sipdroid.net.RtpSocket;
       
    31 import org.sipdroid.net.SipdroidSocket;
       
    32 import org.sipdroid.pjlib.Codec;
       
    33 
       
    34 import android.content.ContentResolver;
       
    35 import android.content.Context;
       
    36 import android.content.SharedPreferences.Editor;
       
    37 import android.media.AudioFormat;
       
    38 import android.media.AudioManager;
       
    39 import android.media.AudioTrack;
       
    40 import android.media.ToneGenerator;
       
    41 import android.os.PowerManager;
       
    42 import android.os.RemoteException;
       
    43 import android.preference.PreferenceManager;
       
    44 import android.provider.Settings;
       
    45 
       
    46 /**
       
    47  * RtpStreamReceiver is a generic stream receiver. It receives packets from RTP
       
    48  * and writes them into an OutputStream.
       
    49  */
       
    50 public class RtpStreamReceiver extends Thread {
       
    51 
       
    52     /** Whether working in debug mode. */
       
    53     public static boolean DEBUG = true;
       
    54 
       
    55     /** Payload type */
       
    56     int p_type;
       
    57 
       
    58     /** Size of the read buffer */
       
    59     public static final int BUFFER_SIZE = 1024;
       
    60 
       
    61     /** Maximum blocking time, spent waiting for reading new bytes [milliseconds] */
       
    62     public static final int SO_TIMEOUT = 200;
       
    63 
       
    64     /** The RtpSocket */
       
    65     private RtpSocket rtp_socket = null;
       
    66 
       
    67     /** Whether it is running */
       
    68     private boolean running;
       
    69     private AudioManager am;
       
    70     private ContentResolver cr;
       
    71     public static int speakermode;
       
    72     private JingleService mJingle;
       
    73 
       
    74     /**
       
    75      * Constructs a RtpStreamReceiver.
       
    76      * 
       
    77      * @param output_stream
       
    78      *            the stream sink
       
    79      * @param socket
       
    80      *            the local receiver SipdroidSocket
       
    81      */
       
    82     public RtpStreamReceiver(SipdroidSocket socket, int payload_type) {
       
    83 	init(socket);
       
    84 	p_type = payload_type;
       
    85     }
       
    86 
       
    87     /** Inits the RtpStreamReceiver */
       
    88     private void init(SipdroidSocket socket) {
       
    89 	if (socket != null)
       
    90 	    rtp_socket = new RtpSocket(socket);
       
    91     }
       
    92 
       
    93     /** Whether is running */
       
    94     public boolean isRunning() {
       
    95 	return running;
       
    96     }
       
    97 
       
    98     /** Stops running */
       
    99     public void halt() {
       
   100 	running = false;
       
   101     }
       
   102 
       
   103     public int speaker(int mode) {
       
   104 	int old = speakermode;
       
   105 
       
   106 	if (Call.headset > 0 && mode == AudioManager.MODE_NORMAL)
       
   107 	    return old;
       
   108 	saveVolume();
       
   109 	setMode(speakermode = mode);
       
   110 	restoreVolume();
       
   111 	return old;
       
   112     }
       
   113 
       
   114     double smin = 200,s;
       
   115     public static int nearend;
       
   116 
       
   117     void calc(short[] lin,int off,int len) {
       
   118 	int i,j;
       
   119 	double sm = 30000,r;
       
   120 
       
   121 	for (i = 0; i < len; i += 5) {
       
   122 	    j = lin[i+off];
       
   123 	    s = 0.03*Math.abs(j) + 0.97*s;
       
   124 	    if (s < sm) sm = s;
       
   125 	    if (s > smin) nearend = 3000/5;
       
   126 	    else if (nearend > 0) nearend--;
       
   127 	}
       
   128 	for (i = 0; i < len; i++) {
       
   129 	    j = lin[i+off];
       
   130 	    if (j > 6550)
       
   131 		lin[i+off] = 6550*5;
       
   132 	    else if (j < -6550)
       
   133 		lin[i+off] = -6550*5;
       
   134 	    else
       
   135 		lin[i+off] = (short)(j*5);
       
   136 	}
       
   137 	r = (double)len/100000;
       
   138 	smin = sm*r + smin*(1-r);
       
   139     }
       
   140 
       
   141     static void setStreamVolume(final int stream,final int vol,final int flags) {
       
   142 	(new Thread() {
       
   143 	    public void run() {
       
   144 		AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
       
   145 		am.setStreamVolume(stream, vol, flags);
       
   146 		if (stream == AudioManager.STREAM_MUSIC) restored = true;
       
   147 	    }
       
   148 	}).start();
       
   149     }
       
   150 
       
   151     static boolean restored;
       
   152 
       
   153     public static float getEarGain() {
       
   154 	try {
       
   155 	    return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString(Call.headset > 0?"heargain":"eargain", "0.25"));
       
   156 	} catch (NumberFormatException i) {
       
   157 	    return (float)0.25;
       
   158 	}			
       
   159     }
       
   160 
       
   161     void restoreVolume() {
       
   162 	switch (am.getMode()) {
       
   163 	    case AudioManager.MODE_IN_CALL:
       
   164 		setStreamVolume(AudioManager.STREAM_RING,(int)(
       
   165 		    am.getStreamMaxVolume(AudioManager.STREAM_RING)*
       
   166 		    getEarGain()), 0);
       
   167 		track.setStereoVolume(AudioTrack.getMaxVolume()*
       
   168 		    getEarGain()
       
   169 		    ,AudioTrack.getMaxVolume()*
       
   170 		    getEarGain());
       
   171 		break;
       
   172 	    case AudioManager.MODE_NORMAL:
       
   173 		track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume());
       
   174 		break;
       
   175 	}
       
   176 	setStreamVolume(AudioManager.STREAM_MUSIC,
       
   177 	    PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("volume"+speakermode, 
       
   178 		am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)*
       
   179 		(speakermode == AudioManager.MODE_NORMAL?4:3)/4
       
   180 	    ),0);
       
   181     }
       
   182 
       
   183     void saveVolume() {
       
   184 	if (restored) {
       
   185 	    Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
       
   186 	    edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC));
       
   187 	    edit.commit();
       
   188 	}
       
   189     }
       
   190 
       
   191     void saveSettings() {
       
   192 	if (!PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",false)) {
       
   193 	    int oldvibrate = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
       
   194 	    int oldvibrate2 = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
       
   195 	    if (!PreferenceManager.getDefaultSharedPreferences(Call.mContext).contains("oldvibrate2"))
       
   196 		oldvibrate2 = AudioManager.VIBRATE_SETTING_ON;
       
   197 	    int oldpolicy = android.provider.Settings.System.getInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, 
       
   198 		Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
       
   199 	    Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
       
   200 	    edit.putInt("oldvibrate", oldvibrate);
       
   201 	    edit.putInt("oldvibrate2", oldvibrate2);
       
   202 	    edit.putInt("oldpolicy", oldpolicy);
       
   203 	    edit.putInt("oldring",am.getStreamVolume(AudioManager.STREAM_RING));
       
   204 	    edit.putBoolean("oldvalid", true);
       
   205 	    edit.commit();
       
   206 	}
       
   207     }
       
   208 
       
   209     public static void setMode(int mode) {
       
   210 	Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
       
   211 	edit.putBoolean("setmode", mode != AudioManager.MODE_NORMAL);
       
   212 	edit.commit();
       
   213 	AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
       
   214 	am.setMode(mode);
       
   215     }
       
   216 
       
   217     public static void restoreMode() {
       
   218 	if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("setmode",true)) {
       
   219 	    setMode(AudioManager.MODE_NORMAL);
       
   220 	}
       
   221     }
       
   222 
       
   223     public static void restoreSettings() {
       
   224 	if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",true)) {
       
   225 	    AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
       
   226 	    ContentResolver cr = Call.mContext.getContentResolver();
       
   227 	    int oldvibrate = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate",0);
       
   228 	    int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate2",0);
       
   229 	    int oldpolicy = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldpolicy",0);
       
   230 	    am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,oldvibrate);
       
   231 	    am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,oldvibrate2);
       
   232 	    Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY, oldpolicy);
       
   233 	    setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldring",0), 0);
       
   234 	    Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
       
   235 	    edit.putBoolean("oldvalid", false);
       
   236 	    edit.commit();
       
   237 	    PowerManager pm = (PowerManager) Call.mContext.getSystemService(Context.POWER_SERVICE);
       
   238 	    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
       
   239 		PowerManager.ACQUIRE_CAUSES_WAKEUP, "Sipdroid.RtpStreamReceiver");
       
   240 	    wl.acquire(1000);
       
   241 	}
       
   242 	restoreMode();
       
   243     }
       
   244 
       
   245     public static float good, late, lost, loss;
       
   246     public static int timeout;
       
   247 
       
   248     void empty() {
       
   249 	try {
       
   250 	    rtp_socket.getDatagramSocket().setSoTimeout(1);
       
   251 	    for (;;)
       
   252 		rtp_socket.receive(rtp_packet);
       
   253 	} catch (SocketException e2) {
       
   254 	    e2.printStackTrace();
       
   255 	} catch (IOException e) {
       
   256 	}
       
   257 	try {
       
   258 	    rtp_socket.getDatagramSocket().setSoTimeout(1000);
       
   259 	} catch (SocketException e2) {
       
   260 	    e2.printStackTrace();
       
   261 	}
       
   262     }
       
   263 
       
   264     RtpPacket rtp_packet;
       
   265     AudioTrack track;
       
   266 
       
   267     /** Runs it in a new Thread. */
       
   268     public void run() {
       
   269 	boolean nodata = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("nodata",false);
       
   270 
       
   271 	if (rtp_socket == null) {
       
   272 	    if (DEBUG)
       
   273 		println("ERROR: RTP socket is null");
       
   274 	    return;
       
   275 	}
       
   276 
       
   277 	byte[] buffer = new byte[BUFFER_SIZE+12];
       
   278 	byte[] buffer_gsm = new byte[33+12];
       
   279 	int i;
       
   280 	rtp_packet = new RtpPacket(buffer, 0);
       
   281 
       
   282 	if (DEBUG)
       
   283 	    println("Reading blocks of max " + buffer.length + " bytes");
       
   284 
       
   285 	running = true;
       
   286 	speakermode = Call.docked > 0?AudioManager.MODE_NORMAL:AudioManager.MODE_IN_CALL;
       
   287 	restored = false;
       
   288 
       
   289 	android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
       
   290 	am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
       
   291 	cr = Call.mContext.getContentResolver();
       
   292 	saveSettings();
       
   293 	Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,Settings.System.WIFI_SLEEP_POLICY_NEVER);
       
   294 	am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,AudioManager.VIBRATE_SETTING_OFF);
       
   295 	am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,AudioManager.VIBRATE_SETTING_OFF);
       
   296 	int oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
       
   297 	track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
       
   298 	    BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM);
       
   299 	short lin[] = new short[BUFFER_SIZE];
       
   300 	short lin2[] = new short[BUFFER_SIZE];
       
   301 	int user, server, lserver, luser, cnt, todo, headroom, len = 0, seq = 0, cnt2 = 0, m = 1,
       
   302 	expseq, getseq, vm = 1, gap, gseq;
       
   303 	timeout = 1;
       
   304 	boolean islate;
       
   305 	user = 0;
       
   306 	lserver = 0;
       
   307 	luser = -8000;
       
   308 	cnt = 0;
       
   309 	switch (p_type) {
       
   310 	    case 3:
       
   311 		Codec.init();
       
   312 		break;
       
   313 	    case 0:
       
   314 	    case 8:
       
   315 		G711.init();
       
   316 		break;
       
   317 	}
       
   318 	ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*0.95));
       
   319 	track.play();
       
   320 	if (Call.headset > 0 && Call.oRingtone != null) {
       
   321 	    ToneGenerator tg2 = new ToneGenerator(AudioManager.STREAM_RING,(int)(ToneGenerator.MAX_VOLUME*2*0.95));
       
   322 	    tg2.startTone(ToneGenerator.TONE_SUP_RINGTONE);
       
   323 	    System.gc();
       
   324 	    tg2.stopTone();
       
   325 	} else
       
   326 	    System.gc();
       
   327 	while (running) {
       
   328 	    if (Call.call_state == Call.UA_STATE_HOLD) {
       
   329 		tg.stopTone();
       
   330 		track.pause();
       
   331 		while (running && Call.call_state == Call.UA_STATE_HOLD) {
       
   332 		    try {
       
   333 			sleep(1000);
       
   334 		    } catch (InterruptedException e1) {
       
   335 			e1.printStackTrace();
       
   336 		    }
       
   337 		}
       
   338 		track.play();
       
   339 		System.gc();
       
   340 		timeout = 1;
       
   341 		seq = 0;
       
   342 	    }
       
   343 	    try {
       
   344 		rtp_socket.receive(rtp_packet);
       
   345 		if (timeout != 0) {
       
   346 		    tg.stopTone();
       
   347 		    track.pause();
       
   348 		    user += track.write(lin2,0,BUFFER_SIZE);
       
   349 		    user += track.write(lin2,0,BUFFER_SIZE);
       
   350 		    track.play();
       
   351 		    cnt += 2*BUFFER_SIZE;
       
   352 		    empty();
       
   353 		}
       
   354 		timeout = 0;
       
   355 	    } catch (IOException e) {
       
   356 		if (timeout == 0 && nodata) {
       
   357 		    tg.startTone(ToneGenerator.TONE_SUP_RINGTONE);
       
   358 		}
       
   359 		rtp_socket.getDatagramSocket().disconnect();
       
   360 		if (++timeout > 22) {
       
   361 		    try {
       
   362 			mJingle.closeCall();
       
   363 		    } catch (RemoteException e1) {
       
   364 			e1.printStackTrace();
       
   365 		    }
       
   366 		    break;
       
   367 		}
       
   368 	    }
       
   369 	    if (running && timeout == 0) {		
       
   370 		gseq = rtp_packet.getSequenceNumber();
       
   371 		if (seq == gseq) {
       
   372 		    m++;
       
   373 		    continue;
       
   374 		}
       
   375 
       
   376 		server = track.getPlaybackHeadPosition();
       
   377 		headroom = user-server;
       
   378 
       
   379 		if (headroom > 1500)
       
   380 		    cnt += len;
       
   381 		else
       
   382 		    cnt = 0;
       
   383 
       
   384 		if (lserver == server)
       
   385 		    cnt2++;
       
   386 		else
       
   387 		    cnt2 = 0;
       
   388 
       
   389 		if (cnt <= 500 || cnt2 >= 2 || headroom - 875 < len) {
       
   390 		    switch (rtp_packet.getPayloadType()) {
       
   391 			case 0:
       
   392 			    len = rtp_packet.getPayloadLength();
       
   393 			    G711.ulaw2linear(buffer, lin, len);
       
   394 			    break;
       
   395 			case 8:
       
   396 			    len = rtp_packet.getPayloadLength();
       
   397 			    G711.alaw2linear(buffer, lin, len);
       
   398 			    break;
       
   399 			case 3:
       
   400 			    for (i = 12; i < 45; i++)
       
   401 				buffer_gsm[i] = buffer[i];
       
   402 			    len = Codec.decode(buffer_gsm, lin, 0);
       
   403 			    break;
       
   404 		    }
       
   405 
       
   406 		    if (speakermode == AudioManager.MODE_NORMAL)
       
   407 			calc(lin,0,len);
       
   408 		}
       
   409 
       
   410 		if (headroom < 250) { 
       
   411 		    todo = 875 - headroom;
       
   412 		    println("insert "+todo);
       
   413 		    islate = true;
       
   414 		    user += track.write(lin2,0,todo);
       
   415 		} else
       
   416 		    islate = false;
       
   417 
       
   418 		if (cnt > 500 && cnt2 < 2) {
       
   419 		    todo = headroom - 875;
       
   420 		    println("cut "+todo);
       
   421 		    if (todo < len)
       
   422 			user += track.write(lin,todo,len-todo);
       
   423 		} else
       
   424 		    user += track.write(lin,0,len);
       
   425 
       
   426 		seq = gseq;
       
   427 
       
   428 		if (user >= luser + 8000 && Call.call_state == Call.UA_STATE_INCALL) {
       
   429 		    if (luser == -8000 || am.getMode() != speakermode) {
       
   430 			saveVolume();
       
   431 			setMode(speakermode);
       
   432 			restoreVolume();
       
   433 		    }
       
   434 		    luser = user;
       
   435 		}
       
   436 		lserver = server;
       
   437 	    }
       
   438 	}
       
   439 	track.stop();
       
   440 	saveVolume();
       
   441 	setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
       
   442 	restoreSettings();
       
   443 	setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
       
   444 	tg.stopTone();
       
   445 	tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3);
       
   446 	tg.startTone(ToneGenerator.TONE_PROP_PROMPT);
       
   447 	try {
       
   448 	    sleep(500);
       
   449 	} catch (InterruptedException e) {
       
   450 	    e.printStackTrace();
       
   451 	}
       
   452 	tg.stopTone();
       
   453 
       
   454 	rtp_socket.close();
       
   455 	rtp_socket = null;
       
   456 
       
   457 	if (DEBUG)
       
   458 	    println("rtp receiver terminated");
       
   459     }
       
   460 
       
   461     /** Debug output */
       
   462     private static void println(String str) {
       
   463 	System.out.println("RtpStreamReceiver: " + str);
       
   464     }
       
   465 
       
   466     public static int byte2int(byte b) { // return (b>=0)? b : -((b^0xFF)+1);
       
   467 	// return (b>=0)? b : b+0x100;
       
   468 	return (b + 0x100) % 0x100;
       
   469     }
       
   470 
       
   471     public static int byte2int(byte b1, byte b2) {
       
   472 	return (((b1 + 0x100) % 0x100) << 8) + (b2 + 0x100) % 0x100;
       
   473     }
       
   474 }