研究了SipDroid2.7,自己对它的理解也渐渐的清晰了。
那它是怎样实现电话拨打以及电话监听的?它的音频接收以及发送是怎么实现的?它的视频又是怎么一回事?它在模拟器上的端口为什么总是变化的?它又是如何处理登陆超时以及通话出错的?
带着这些疑问进入它的代码思想境界!
使用yate搭配服务器,然后使用了一个yate与SipDroid客户端进行通话!~至于怎么搭配服务器以及SipDroid的配置设置,此处就不讨论了!~
登陆后的标识效果如图:
然后我使用了yate客户端程序拨打了SipDroid程序段上的帐号(banketree),如图:
接通后的效果图像如图:
好了,进入我们的主题了!~
它是怎样实现电话拨打以及电话监听的?
程序进入时会进行服务注册,如下:
-
- / Receiver.engine(this).registerMore();
我们知道Receiver.engine(this) 进行了SipUA引擎的实例化,并开启SipUA引擎,关键就SipUA引擎了!~
-
- public static synchronized SipdroidEngine engine(Context context)
- {
-
- if (mContext == null
- || !context.getClass().getName()
- .contains("ReceiverRestrictedContext"))
- {
- mContext = context;
- }
-
-
- if (mSipdroidEngine == null)
- {
- mSipdroidEngine = new SipdroidEngine();
-
-
- mSipdroidEngine.StartEngine();
-
-
- if (Integer.parseInt(Build.VERSION.SDK) >= 8)
- {
- Bluetooth.init();
- }
- } else
- {
-
- mSipdroidEngine.CheckEngine();
- }
-
-
- context.startService(new Intent(context, RegisterService.class));
-
- return mSipdroidEngine;
- }
而StartEngine()里有开启监听!~
至于里面是怎么实现的,那就涉及到了SipUA封装的一些类以及消息了!~
消息以及协议的通信都是SipProvider类由完成的!~
- public void onReceivedMessage(Transport transport, Message msg)
- {
- if (pm == null)
- {
- pm = (PowerManager) Receiver.mContext.getSystemService(Context.POWER_SERVICE);
- wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Sipdroid.SipProvider");
- }
- wl.acquire();
-
-
- processReceivedMessage(msg);
- wl.release();
- }
向服务器发送信息(发送协议进行登陆以及获取对方信息等等)也是由该类完成的!~如下:
-
-
-
-
-
- private ConnectionIdentifier sendMessage(Message msg, String proto, IpAddress dest_ipaddr, int dest_port, int ttl)
- {
- if(bDebug)
- {
- android.util.Log.i("SipProvider发送消息", "msg:"+msg.toString());
- }
-
- ConnectionIdentifier conn_id = new ConnectionIdentifier(proto, dest_ipaddr, dest_port);
- if (log_all_packets || msg.getLength() > MIN_MESSAGE_LENGTH)
- printLog("Sending message to " + conn_id, LogLevel.MEDIUM);
-
- if (transport_udp && proto.equals(PROTO_UDP))
- {
-
-
- conn_id = null;
- try
- {
-
- udp.sendMessage(msg, dest_ipaddr, dest_port);
- } catch (IOException e)
- {
- printException(e, LogLevel.HIGH);
- return null;
- }
- } else if (transport_tcp && proto.equals(PROTO_TCP))
- {
-
-
- if (connections == null || !connections.containsKey(conn_id))
- {
-
- printLog("no active connection found matching " + conn_id, LogLevel.MEDIUM);
- printLog("open " + proto + " connection to " + dest_ipaddr + ":" + dest_port, LogLevel.MEDIUM);
- TcpTransport conn = null;
- try
- {
- conn = new TcpTransport(dest_ipaddr, dest_port, this);
- } catch (Exception e)
- {
- printLog("connection setup FAILED", LogLevel.HIGH);
- return null;
- }
-
- printLog("connection " + conn + " opened", LogLevel.HIGH);
- addConnection(conn);
- if (!msg.isRegister())
- Receiver.engine(Receiver.mContext).register();
- } else
- {
- printLog("active connection found matching " + conn_id, LogLevel.MEDIUM);
- }
- ConnectedTransport conn = (ConnectedTransport) connections.get(conn_id);
- if (conn != null)
- {
- printLog("sending data through conn " + conn, LogLevel.MEDIUM);
- try
- {
- conn.sendMessage(msg);
- conn_id = new ConnectionIdentifier(conn);
- } catch (IOException e)
- {
- printException(e, LogLevel.HIGH);
- return null;
- }
- } else
- {
-
- printLog("ERROR: conn " + conn_id + " not found: abort.", LogLevel.MEDIUM);
- return null;
- }
- } else
- {
- printWarning("Unsupported protocol (" + proto + "): Message discarded", LogLevel.HIGH);
- return null;
- }
-
- String dest_addr = dest_ipaddr.toString();
- printMessageLog(proto, dest_addr, dest_port, msg.getLength(), msg, "sent");
- return conn_id;
- }
消息的信息格式如下:
……
回到问题中来,监听电话已经明白了,那是如何实现拨打的?
当用户登陆后就会把自己的信息发送给服务端,服务端记录下来,等用户需要时就返回给他,比如我打banketree电话,我没有他的信息我怎么打呀,是吧!~
拨打电话的关键在UserAgent中,其它的都是封装好处理信息的类!~
- public boolean call(String target_url, boolean send_anonymous)
- {
-
- if (Receiver.call_state != UA_STATE_IDLE)
- {
-
-
-
- printLog("Call attempted in state" + this.getSessionDescriptor()
- + " : Failing Request", LogLevel.HIGH);
- return false;
- }
-
-
- hangup();
-
-
- changeStatus(UA_STATE_OUTGOING_CALL, target_url);
-
- String from_url;
-
- if (!send_anonymous)
- {
- from_url = user_profile.from_url;
- } else
- {
- from_url = "sip:[email protected]";
- }
-
-
- createOffer();
-
-
- call = new ExtendedCall(sip_provider, from_url,
- user_profile.contact_url, user_profile.username,
- user_profile.realm, user_profile.passwd, this);
-
-
-
-
- if (target_url.indexOf("@") < 0)
- {
- if (user_profile.realm.equals(Settings.DEFAULT_SERVER))
- target_url = "&" + target_url;
-
- target_url = target_url + "@" + realm;
- }
-
-
-
- String icsi = null;
- if (user_profile.mmtel == true)
- {
- icsi = "\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";
- }
-
-
- target_url = sip_provider.completeNameAddress(target_url).toString();
-
-
- if (user_profile.no_offer)
- {
- call.call(target_url);
- } else
- {
- call.call(target_url, local_session, icsi);
- }
-
- return true;
- }
那它的音频接收以及发送是怎么实现的?
管理音频有一个类,它是JAudioLauncher,当实例化它的时候,它会开启两个线程,一个是RtpStreamReceiver,另一个是RtpStreamReceiver!~
看标题就知道它们一个是发送的,一个是接收的!~
先来看下接收是怎么实现的!~
- public void run()
- {
- boolean nodata = PreferenceManager.getDefaultSharedPreferences(
- Receiver.mContext).getBoolean(
- org.sipdroid.sipua.ui.Settings.PREF_NODATA,
- org.sipdroid.sipua.ui.Settings.DEFAULT_NODATA);
- keepon = PreferenceManager.getDefaultSharedPreferences(
- Receiver.mContext).getBoolean(
- org.sipdroid.sipua.ui.Settings.PREF_KEEPON,
- org.sipdroid.sipua.ui.Settings.DEFAULT_KEEPON);
-
- if (rtp_socket == null)
- {
- if (DEBUG)
- {
- println("ERROR: RTP socket is null(出错:rtp接受套接字出错!)");
- }
- return;
- }
-
-
- byte[] buffer = new byte[BUFFER_SIZE + 12];
-
-
- rtp_packet = new RtpPacket(buffer, 0);
-
- if (DEBUG)
- {
- println("Reading blocks of max (读取快的最大值) = " + buffer.length + " bytes");
- }
-
- running = true;
-
-
- enableBluetooth(PreferenceManager.getDefaultSharedPreferences(
- Receiver.mContext).getBoolean(
- org.sipdroid.sipua.ui.Settings.PREF_BLUETOOTH,
- org.sipdroid.sipua.ui.Settings.DEFAULT_BLUETOOTH));
-
- restored = false;
-
-
- android.os.Process
- .setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
-
- am = (AudioManager) Receiver.mContext
- .getSystemService(Context.AUDIO_SERVICE);
- cr = Receiver.mContext.getContentResolver();
-
-
- saveSettings();
- Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,
- Settings.System.WIFI_SLEEP_POLICY_NEVER);
- am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
- AudioManager.VIBRATE_SETTING_OFF);
- am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,
- AudioManager.VIBRATE_SETTING_OFF);
- if (oldvol == -1)
- {
- oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
- }
-
-
- initMode();
-
-
- setCodec();
-
-
- short lin[] = new short[BUFFER_SIZE];
-
- short lin2[] = new short[BUFFER_SIZE];
- int server, headroom, todo, len = 0, m = 1, expseq, getseq, vm = 1, gap, gseq;
-
- ToneGenerator tg = new ToneGenerator(
- AudioManager.STREAM_VOICE_CALL,
- (int) (ToneGenerator.MAX_VOLUME * 2 * org.sipdroid.sipua.ui.Settings
- .getEarGain()));
-
-
- track.play();
-
-
-
- System.gc();
-
-
- empty();
-
- lockFirst = true;
-
- while (running)
- {
- lock(true);
-
- if (Receiver.call_state == UserAgent.UA_STATE_HOLD)
- {
- lock(false);
-
-
- tg.stopTone();
-
-
- track.pause();
-
- while (running
- && Receiver.call_state == UserAgent.UA_STATE_HOLD)
- {
- try
- {
- sleep(1000);
- } catch (InterruptedException e1)
- {
- }
- }
-
- track.play();
- System.gc();
- timeout = 1;
- luser = luser2 = -8000 * mu;
- }
-
- try
- {
-
- rtp_socket.receive(rtp_packet);
-
-
- if (timeout != 0)
- {
-
- tg.stopTone();
-
-
- track.pause();
-
-
- for (int i = maxjitter * 2; i > 0; i -= BUFFER_SIZE)
- {
- write(lin2, 0, i > BUFFER_SIZE ? BUFFER_SIZE : i);
- }
-
- cnt += maxjitter * 2;
-
-
- track.play();
- empty();
- }
- timeout = 0;
- } catch (IOException e)
- {
- if (timeout == 0 && nodata)
- {
- tg.startTone(ToneGenerator.TONE_SUP_RINGTONE);
- }
-
-
- rtp_socket.getDatagramSocket().disconnect();
-
- if (++timeout > 60)
- {
- Receiver.engine(Receiver.mContext).rejectcall();
- break;
- }
- }
-
-
- if (running && timeout == 0)
- {
-
- gseq = rtp_packet.getSequenceNumber();
-
-
- if (seq == gseq)
- {
- m++;
- continue;
- }
-
-
- gap = (gseq - seq) & 0xff;
-
- if (gap > 240)
- {
- continue;
- }
-
-
- server = track.getPlaybackHeadPosition();
-
-
- headroom = user - server;
-
- if (headroom > 2 * jitter)
- {
- cnt += len;
- } else
- {
- cnt = 0;
- }
-
- if (lserver == server)
- {
- cnt2++;
- } else
- {
- cnt2 = 0;
- }
-
- if (cnt <= 500 * mu || cnt2 >= 2 || headroom - jitter < len
- || p_type.codec.number() != 8
- || p_type.codec.number() != 0)
- {
-
- if (rtp_packet.getPayloadType() != p_type.number
- && p_type.change(rtp_packet.getPayloadType()))
- {
-
- saveVolume();
-
-
- setCodec();
-
-
- restoreVolume();
-
-
- codec = p_type.codec.getTitle();
- }
-
-
- len = p_type.codec.decode(buffer, lin,
- rtp_packet.getPayloadLength());
-
-
-
- if (call_recorder != null)
- {
-
- call_recorder.writeIncoming(lin, 0, len);
- }
-
-
- if (speakermode == AudioManager.MODE_NORMAL)
- {
- calc(lin, 0, len);
- } else if (gain > 1)
- {
- calc2(lin, 0, len);
- }
- }
-
-
- avgheadroom = avgheadroom * 0.99 + (double) headroom * 0.01;
- if (avgcnt++ > 300)
- {
- devheadroom = devheadroom * 0.999
- + Math.pow(Math.abs(headroom - avgheadroom), 2)
- * 0.001;
- }
-
-
- if (headroom < 250 * mu)
- {
- late++;
- newjitter(true);
-
-
- todo = jitter - headroom;
- write(lin2, 0, todo > BUFFER_SIZE ? BUFFER_SIZE : todo);
- }
-
-
- if (cnt > 500 * mu && cnt2 < 2)
- {
- todo = headroom - jitter;
- if (todo < len)
- {
- write(lin, todo, len - todo);
- }
- } else
- {
- write(lin, 0, len);
- }
-
-
- if (seq != 0)
- {
- getseq = gseq & 0xff;
- expseq = ++seq & 0xff;
- if (m == RtpStreamSender.m)
- {
- vm = m;
- }
-
- gap = (getseq - expseq) & 0xff;
- if (gap > 0)
- {
-
- if (gap > 100)
- {
- gap = 1;
- }
- loss += gap;
- lost += gap;
- good += gap - 1;
- loss2++;
- } else
- {
- if (m < vm)
- {
- loss++;
- loss2++;
- }
- }
- good++;
- if (good > 110)
- {
- good *= 0.99;
- lost *= 0.99;
- loss *= 0.99;
- loss2 *= 0.99;
- late *= 0.99;
- }
- }
- m = 1;
- seq = gseq;
-
- if (user >= luser + 8000 * mu
- && (Receiver.call_state == UserAgent.UA_STATE_INCALL || Receiver.call_state == UserAgent.UA_STATE_OUTGOING_CALL))
- {
- if (luser == -8000 * mu || getMode() != speakermode)
- {
-
- saveVolume();
-
-
- setMode(speakermode);
-
-
- restoreVolume();
- }
-
- luser = user;
-
- if (user >= luser2 + 160000 * mu)
- {
-
- newjitter(false);
- }
- }
- lserver = server;
- }
- }
再看下发送包是怎么实现的,发送声音肯定是先录制,后读取,再发送!~如下:
- public void run()
- {
-
-
-
-
-
- WifiManager wm = (WifiManager) Receiver.mContext
- .getSystemService(Context.WIFI_SERVICE);
- long lastscan = 0, lastsent = 0;
-
- if (rtp_socket == null)
- return;
- int seqn = 0;
- long time = 0;
- double p = 0;
-
-
- boolean improve = PreferenceManager.getDefaultSharedPreferences(
- Receiver.mContext).getBoolean(Settings.PREF_IMPROVE,
- Settings.DEFAULT_IMPROVE);
-
-
- boolean selectWifi = PreferenceManager.getDefaultSharedPreferences(
- Receiver.mContext).getBoolean(
- org.sipdroid.sipua.ui.Settings.PREF_SELECTWIFI,
- org.sipdroid.sipua.ui.Settings.DEFAULT_SELECTWIFI);
-
- int micgain = 0;
- long last_tx_time = 0;
- long next_tx_delay;
- long now;
- running = true;
- m = 1;
- int dtframesize = 4;
-
-
- android.os.Process
- .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
-
-
- mu = p_type.codec.samp_rate() / 8000;
- int min = AudioRecord.getMinBufferSize(p_type.codec.samp_rate(),
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT);
-
- if (min == 640)
- {
- if (frame_size == 960)
- frame_size = 320;
- if (frame_size == 1024)
- frame_size = 160;
- min = 4096 * 3 / 2;
- } else if (min < 4096)
- {
- if (min <= 2048 && frame_size == 1024)
- frame_size /= 2;
- min = 4096 * 3 / 2;
- } else if (min == 4096)
- {
- min *= 3 / 2;
- if (frame_size == 960)
- frame_size = 320;
- } else
- {
- if (frame_size == 960)
- frame_size = 320;
- if (frame_size == 1024)
- frame_size *= 2;
- }
-
-
- frame_rate = p_type.codec.samp_rate() / frame_size;
- long frame_period = 1000 / frame_rate;
- frame_rate *= 1.5;
-
-
- byte[] buffer = new byte[frame_size + 12];
-
-
- RtpPacket rtp_packet = new RtpPacket(buffer, 0);
-
-
- rtp_packet.setPayloadType(p_type.number);
-
-
- if (DEBUG)
- println("Reading blocks of (读取块大小)" + buffer.length + " bytes");
-
- println("Sample rate (采样率) = " + p_type.codec.samp_rate());
- println("Buffer size(缓冲区大小) = " + min);
-
-
- AudioRecord record = null;
-
-
- short[] lin = new short[frame_size * (frame_rate + 1)];
- int num, ring = 0, pos;
-
-
- random = new Random();
-
-
- InputStream alerting = null;
- try
- {
-
- alerting = Receiver.mContext.getAssets().open("alerting");
- } catch (IOException e2)
- {
- if (!Sipdroid.release)
- e2.printStackTrace();
- }
-
-
- p_type.codec.init();
-
- if(Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender", "音频发送开始啦");
- }
-
-
- while (running)
- {
-
- if (changed || record == null)
- {
- if (record != null)
- {
-
- record.stop();
- record.release();
- if (RtpStreamReceiver.samsung)
- {
- AudioManager am = (AudioManager) Receiver.mContext
- .getSystemService(Context.AUDIO_SERVICE);
- am.setMode(AudioManager.MODE_IN_CALL);
- am.setMode(AudioManager.MODE_NORMAL);
- }
- }
-
-
- changed = false;
-
-
- record = new AudioRecord(MediaRecorder.AudioSource.MIC,
- p_type.codec.samp_rate(),
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT, min);
-
- if(Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender", "构造音频录制实例");
- }
-
-
- if (record.getState() != AudioRecord.STATE_INITIALIZED)
- {
-
- Receiver.engine(Receiver.mContext).rejectcall();
- record = null;
- break;
- }
-
-
- record.startRecording();
-
-
- micgain = (int) (Settings.getMicGain() * 10);
- }
-
-
-
- if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD)
- {
-
- if (Receiver.call_state == UserAgent.UA_STATE_HOLD)
- {
-
- RtpStreamReceiver.restoreMode();
- }
-
- if(Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender", "挂断电话则停止录制");
- }
-
-
- record.stop();
-
-
- while (running
- && (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD))
- {
- try
- {
- sleep(1000);
- } catch (InterruptedException e1)
- {
- }
- }
-
-
- record.startRecording();
- }
-
-
- if (dtmf.length() != 0)
- {
-
- byte[] dtmfbuf = new byte[dtframesize + 12];
- RtpPacket dt_packet = new RtpPacket(dtmfbuf, 0);
-
-
- dt_packet.setPayloadType(dtmf_payload_type);
-
-
- dt_packet.setPayloadLength(dtframesize);
- dt_packet.setSscr(rtp_packet.getSscr());
- long dttime = time;
- int duration;
-
- for (int i = 0; i < 6; i++)
- {
- time += 160;
- duration = (int) (time - dttime);
- dt_packet.setSequenceNumber(seqn++);
- dt_packet.setTimestamp(dttime);
- dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));
- dtmfbuf[13] = (byte) 0x0a;
- dtmfbuf[14] = (byte) (duration >> 8);
- dtmfbuf[15] = (byte) duration;
- try
- {
-
- rtp_socket.send(dt_packet);
-
- if (Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender",
- "第一次发送声音包 大小" + dt_packet.getLength()
- + " " + dt_packet.getPacket());
- }
-
- if(bShowVoiceDecodeData)
- {
-
- }
-
- sleep(20);
- } catch (Exception e1)
- {
- }
- }
-
-
- for (int i = 0; i < 3; i++)
- {
- duration = (int) (time - dttime);
- dt_packet.setSequenceNumber(seqn);
- dt_packet.setTimestamp(dttime);
- dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));
- dtmfbuf[13] = (byte) 0x8a;
- dtmfbuf[14] = (byte) (duration >> 8);
- dtmfbuf[15] = (byte) duration;
- try
- {
-
- rtp_socket.send(dt_packet);
-
- if (Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender",
- "第二次发送声音包 大小" + dt_packet.getLength()
- + " " + dt_packet.getPacket());
- }
-
- if(bShowVoiceDecodeData)
- {
-
- }
- } catch (Exception e1)
- {
- }
- }
- time += 160;
- seqn++;
- dtmf = dtmf.substring(1);
- }
-
-
- if (frame_size < 480)
- {
- now = System.currentTimeMillis();
- next_tx_delay = frame_period - (now - last_tx_time);
- last_tx_time = now;
- if (next_tx_delay > 0)
- {
- try
- {
- sleep(next_tx_delay);
- } catch (InterruptedException e1)
- {
- }
- last_tx_time += next_tx_delay - sync_adj;
- }
- }
-
-
- pos = (ring + delay * frame_rate * frame_size)
- % (frame_size * (frame_rate + 1));
-
-
- num = record.read(lin, pos, frame_size);
-
- if (num <= 0)
- continue;
-
-
- if (!p_type.codec.isValid())
- continue;
-
-
-
- if (call_recorder != null)
- {
-
- call_recorder.writeOutgoing(lin, pos, num);
- }
-
- if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL)
- {
- calc(lin, pos, num);
- if (RtpStreamReceiver.nearend != 0
- && RtpStreamReceiver.down_time == 0)
- {
- noise(lin, pos, num, p / 2);
- }
- else if (nearend == 0)
- {
- p = 0.9 * p + 0.1 * s;
- }
- } else
- {
- switch (micgain)
- {
- case 1:
- calc1(lin, pos, num);
- break;
- case 2:
- calc2(lin, pos, num);
- break;
- case 10:
- calc10(lin, pos, num);
- break;
- }
- }
-
- iCount++;
-
-
- if (Receiver.call_state != UserAgent.UA_STATE_INCALL
- && Receiver.call_state != UserAgent.UA_STATE_OUTGOING_CALL
- && alerting != null)
- {
- try
- {
- if (alerting.available() < num / mu)
- {
- alerting.reset();
- }
- alerting.read(buffer, 12, num / mu);
- } catch (IOException e)
- {
- if (!Sipdroid.release)
- {
- e.printStackTrace();
- }
- }
- if (p_type.codec.number() != 8)
- {
- G711.alaw2linear(buffer, lin, num, mu);
- num = p_type.codec.encode(lin, 0, buffer, num);
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- } else
- {
- num = p_type.codec.encode(lin, ring
- % (frame_size * (frame_rate + 1)), buffer, num);
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
-
-
- ring += frame_size;
- rtp_packet.setSequenceNumber(seqn++);
- rtp_packet.setTimestamp(time);
- rtp_packet.setPayloadLength(num);
-
-
- now = SystemClock.elapsedRealtime();
-
- if (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan
- || now - lastsent > 500)
- {
- try
- {
- lastsent = now;
- rtp_socket.send(rtp_packet);
-
- if (m > 1
- && (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan))
- {
- for (int i = 1; i < m; i++)
- rtp_socket.send(rtp_packet);
- }
-
- if (Sipdroid.VoiceDebug)
- {
- Log.i("RtpStreamSender",
- "第三次发送声音包 大小" + rtp_packet.getLength()
- + " " + rtp_packet.getPacket());
- }
-
-
-
-
-
- } catch (Exception e)
- {
- }
- }
-
-
- if (p_type.codec.number() == 9)
- {
- time += frame_size / 2;
- }
- else
- {
- time += frame_size;
- }
-
- if (RtpStreamReceiver.good != 0
- && RtpStreamReceiver.loss2 / RtpStreamReceiver.good > 0.01)
- {
- if (selectWifi && Receiver.on_wlan && now - lastscan > 10000)
- {
- wm.startScan();
- lastscan = now;
- }
- if (improve
- && delay == 0
- && (p_type.codec.number() == 0
- || p_type.codec.number() == 8 || p_type.codec
- .number() == 9))
- {
- m = 2;
- }
- else
- {
- m = 1;
- }
- } else
- {
- m = 1;
- }
- }
好了,进入下一个问题,它的视频又是怎么一回事?此处不谈它的视频编码,直接介绍涉及它的流程!~
涉及视频的类有:VideoCamera、VideoCameraNew、VideoCameraNew2、VideoPreview!~ 而是否使用视频,关键在CallScreen类,CallScreen类是通话的界面!~
如下是否使用视频的代码,该代码在CallScreen中!~
之后就进入到涉及视频的类VideoCamera中了!~
它在模拟器上的端口为什么总是变化的?
抓包分析下,如图:
yate服务端第一次记录了我的rport为1849,从图中发现它是与服务器通信的端口!~服务器中也把它当做端口记录!~而SipUA客户端是使用了UDP套接字自定义了一个37850端口,这个端口一直到退出才改变,而yate服务端第一次记录了我的rport为2251,也就是说服务器记录的rport的端口是一直在发生改变的!~所以下次用户拨打对方,向服务器索取对方信息时出错,就有可能会直接挂掉!~
rport在Sip中的定义是rport方式主要是对sip信令中Via字头的扩展,不过同时也要求SIP Proxy支持该功能。NAT之后的sip client在发送请求的时候在via字头中添加rport字段,该消息经发出后路由到SIP Proxy,SIP Proxy通过检查消息的源地址和Via字段中的地址,得知该client处于NAT之后,并且基于已有的rport,将消息的真实地址即公网上的地址通过received和rport字段返回给client端,这样client就知道自己真实的公网地址,可以解决信令穿越的问题。
而有网友提出,使用Android模拟器通过路由器时端口会发生变化!~ 不知道这是不是真的!