我正在为Android开发SIP客户端并且有问题。问题是我连接两个客户端时没有音频。我正在使用的服务器是www.minisipserver.com。每次调用SipAudioCall.Listener中的onCallEstablished方法。
这是扩展BroadcastReceiver的类,它正在侦听调用。 `
package uk.co.tbw.sip.calling;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.sip.SipAudioCall;
import android.net.sip.SipException;
import android.net.sip.SipProfile;
import uk.co.tbw.utils.TBWLogger;
public class IncomingCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SipAudioCall incomingCall = null;
try {
Call callActivity = (Call) context;
SipAudioCall.Listener listener = new myListener(context);
incomingCall = callActivity.mManager.takeAudioCall(intent, listener);
incomingCall.startAudio();
callActivity.mAudioCall = incomingCall;
callActivity.updateStatus(incomingCall);
} catch (SipException e) {
if (incomingCall != null) {
incomingCall.close();
e.printStackTrace();
}
}
}
class myListener extends SipAudioCall.Listener {
private Context context;
public myListener(Context context) {
this.context = context;
}
@Override
public void onRinging(SipAudioCall call, SipProfile caller) {
try {
call.answerCall(30);
} catch (SipException e) {
e.printStackTrace();
}
}
@Override
public void onReadyToCall(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onReadyToCall : " + call.toString());
}
@Override
public void onCalling(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onCalling : " + call.toString());
}
@Override
public void onRingingBack(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onRingingBack : " + call.toString());
}
@Override
public void onCallEstablished(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onCallEstablished : " + call.toString());
if (call.isInCall()) {
TBWLogger.d("IncomingCallReceiver.java isInCall : " + call.toString());
}
if (call.isOnHold()) {
TBWLogger.d("IncomingCallReceiver.java isOnHold : " + call.toString());
}
if (call.isMuted()) {
TBWLogger.d("IncomingCallReceiver.java isMuted : " + call.toString());
}
call.startAudio();
}
@Override
public void onCallEnded(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onCallEnded : " + call.toString());
}
@Override
public void onCallBusy(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onCallBusy : " + call.toString());
}
@Override
public void onCallHeld(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onCallHeld : " + call.toString());
}
@Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
TBWLogger.d("IncomingCallReceiver.java IncomingCallReceiver.java onError : " + call.toString() + "; errorCode: " + errorCode + "; errorMessage: " + errorMessage);
}
@Override
public void onChanged(SipAudioCall call) {
TBWLogger.d("IncomingCallReceiver.java onReadyToCall : " + call.toString());
}
}
}
`
Call.java活动
package uk.co.tbw.sip.calling;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.sip.SipAudioCall;
import android.net.sip.SipException;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
import android.net.sip.SipRegistrationListener;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.c77.androidstreamingclient.lib.rtp.RtpMediaDecoder;
import java.text.ParseException;
import uk.co.tbw.R;
import uk.co.tbw.utils.TBWLogger;
public class Call extends AppCompatActivity {
public static final int REQUEST_PERMISSION_CODE = 1567;
public String mSipAddress = null;
public SipManager mManager = null;
public SipProfile mProfile = null;
public SipAudioCall mAudioCall = null;
public IncomingCallReceiver mCallReceiver;
private static final int CALL_ADDRESS = 1;
private static final int SET_AUTH_INFO = 2;
private static final int UPDATE_SETTINGS_DIALOG = 3;
private static final int HANG_UP = 4;
private RtpMediaDecoder rtpMediaDecoder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Button callBtn = (Button) findViewById(R.id.answer_btn);
Button closeBtn = (Button) findViewById(R.id.close_btn);
SurfaceView view = new SurfaceView(this);
rtpMediaDecoder = new RtpMediaDecoder(view);
rtpMediaDecoder.start();
callBtn.setOnClickListener(v -> {
EditText textField = (EditText) findViewById(R.id.userToCallEditText);
mSipAddress = textField.getText().toString();
initiateCall();
});
closeBtn.setOnClickListener(v -> {
if (mAudioCall != null) {
try {
mAudioCall.endCall();
TBWLogger.d("Call.java endCall");
} catch (SipException e) {
Log.d("WalkieTalkieActivity/onOptionsItemSelected",
"Error ending call.", e);
}
mAudioCall.close();
}
});
IntentFilter filter = new IntentFilter();
filter.addAction("android.SipDemo.INCOMING_CALL");
mCallReceiver = new IncomingCallReceiver();
this.registerReceiver(mCallReceiver, filter);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
@Override
protected void onStart() {
super.onStart();
initializeManager();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mAudioCall != null) {
mAudioCall.close();
}
closeLocalProfile();
if (mCallReceiver != null) {
this.unregisterReceiver(mCallReceiver);
}
rtpMediaDecoder.release();
}
@Override
protected void onStop() {
rtpMediaDecoder.release();
super.onStop();
}
private void closeLocalProfile() {
if (mManager == null) {
return;
}
try {
if (mProfile != null) {
mManager.close(mProfile.getUriString());
}
} catch (SipException e) {
Log.d("CallActivity/onDestroy", "Failed to close local profile.", e);
}
}
private void initializeManager() {
TBWLogger.d("initializeManager()");
if (mManager == null) {
mManager = SipManager.newInstance(this);
}
initializeLocalProfile();
}
private void initializeLocalProfile() {
TBWLogger.d("initializeLocalProfile");
if (mManager == null) {
return;
}
if (mProfile != null) {
closeLocalProfile();
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String username = preferences.getString("namePref", "");
String domain = preferences.getString("domainPref", "");
String password = preferences.getString("passPref", "");
if (username.length() == 0 || domain.length() == 0 || password.length() == 0) { //|| password.length() == 0
showDialog(UPDATE_SETTINGS_DIALOG);
return;
}
try {
TBWLogger.d("Building new sipProfile");
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword(password);
mProfile = builder.build();
Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
mManager.open(mProfile, pendingIntent, new SipRegistrationListener() {
@Override
public void onRegistering(String localProfileUri) {
TBWLogger.d("onRegistering");
updateStatus("Registering with SIP Server...");
}
@Override
public void onRegistrationDone(String localProfileUri, long expiryTime) {
TBWLogger.d("onRegistrationDone");
updateStatus("Ready");
}
@Override
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) {
TBWLogger.d("onRegistrationFailed:" + " errorMessage:" + errorMessage + " errorCode:" + errorCode
+ " localProfile:" + localProfileUri);
updateStatus("Registration failed. Please check settings.");
}
});
} catch (ParseException e) {
updateStatus("Connection Error.");
e.printStackTrace();
} catch (SipException e) {
updateStatus("Connection Error.");
e.printStackTrace();
}
}
public void initiateCall() {
updateStatus(mSipAddress);
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
@Override
public void onReadyToCall(SipAudioCall call) {
TBWLogger.d("Call.java onReadyToCall: " + call);
}
@Override
public void onRingingBack(SipAudioCall call) {
TBWLogger.d("Call.java onRingingBack: " + call);
}
@Override
public void onCallBusy(SipAudioCall call) {
TBWLogger.d("Call.java onCallBusy: " + call);
}
@Override
public void onCallHeld(SipAudioCall call) {
TBWLogger.d("Call.java onCallHeld: " + call);
}
@Override
public void onChanged(SipAudioCall call) {
TBWLogger.d("Call.java onChanged: " + call);
}
@Override
public void onCallEstablished(SipAudioCall call) {
// AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
// AudioGroup audioGroup = new AudioGroup();
// audioGroup.setMode(AudioGroup.MODE_NORMAL);
// AudioStream audioStream = null;
// try {
// audioStream = new AudioStream(InetAddress.getByAddress(IncomingCallReceiver.getLocalIPAddress()));
// } catch (SocketException e) {
// e.printStackTrace();
// } catch (UnknownHostException e) {
// e.printStackTrace();
// }
// audioStream.setCodec(AudioCodec.PCMU);
// audioStream.setMode(RtpStream.MODE_NORMAL);
// //set receiver(vlc player) machine ip address(please update with your machine ip)
// try {
// audioStream.associate(InetAddress.getByAddress(new byte[] {(byte)192, (byte)168, (byte)1, (byte)19 }), 22222);
// } catch (UnknownHostException e) {
// e.printStackTrace();
// }
// audioStream.join(audioGroup);
//call.setSpeakerMode(true);
call.startAudio();
// if (call.isMuted()) {
// call.toggleMute();
// }
updateStatus(call);
mAudioCall.startAudio();
//mAudioCall.setSpeakerMode(true);
TBWLogger.d("Call.java onCallEstablished(): ");
}
@Override
public void onRinging(SipAudioCall call, SipProfile caller) {
Toast.makeText(Call.this, "Calling", Toast.LENGTH_LONG).show();
try {
call.answerCall(30);
} catch (SipException e) {
e.printStackTrace();
}
TBWLogger.d("Call.java onRinging(): ");
}
@Override
public void onCalling(SipAudioCall call) {
Toast.makeText(Call.this, "Calling", Toast.LENGTH_LONG).show();
TBWLogger.d("Call.java onRinging(): ");
}
@Override
public void onCallEnded(SipAudioCall call) {
updateStatus("Ready");
TBWLogger.d("Call.java onCallEnded(): ");
}
@Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
TBWLogger.d("Call.java onError: errorCode: " + errorCode + "; errorMessage: " + errorMessage);
updateStatus("Call.java onError: errorCode: " + errorCode + "; errorMessage: " + errorMessage);
}
};
mAudioCall = mManager.makeAudioCall(mProfile.getUriString(), mSipAddress, listener, 30);
} catch (SipException e) {
Log.i("InitiateCall", "Error when trying to close manager", e);
if (mProfile != null) {
try {
mManager.close(mProfile.getUriString());
} catch (SipException e1) {
Log.i("InitiateCall", "Error when trying to close manager", e1);
e1.printStackTrace();
}
}
if (mAudioCall != null) {
mAudioCall.close();
}
}
}
public void updateStatus(String s) {
this.runOnUiThread(() -> {
TextView label = (TextView) findViewById(R.id.label);
label.setText(s);
});
}
public void updateStatus(SipAudioCall s) {
String userName = s.getPeerProfile().getDisplayName();
if (userName == null) {
userName = s.getPeerProfile().getUserName();
}
updateStatus(userName + "@" + s.getPeerProfile().getSipDomain());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case SET_AUTH_INFO:
updatePreferences();
break;
}
return true;
}
//TODO: check the break statements
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case CALL_ADDRESS:
LayoutInflater factory = LayoutInflater.from(this);
final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
return new AlertDialog.Builder(this)
.setTitle("Call Someone")
.setView(textBoxView)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
EditText textField = (EditText) (textBoxView.findViewById(R.id.call_address_edit));
mSipAddress = textField.getText().toString();
initiateCall();
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).create();
case UPDATE_SETTINGS_DIALOG:
return new AlertDialog.Builder(this)
.setMessage("Please update your SIP Account Settings.")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
updatePreferences();
}
})
.setNegativeButton(
android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Noop.
}
})
.create();
}
return null;
}
private void updatePreferences() {
Intent settingsActivity = new Intent(getBaseContext(), SipSetting.class);
startActivity(settingsActivity);
}
}
`
Manifest`
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CONFIGURE_SIP" />
<uses-permission android:name="android.software.sip" android:required="true" />
<uses-permission android:name="android.software.sip.voip" android:required="true" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CONFIGURE_SIP" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.hardware.wifi" android:required="true"/>
<uses-permission android:name="android.software.sip.voip" android:required="true" />
<uses-permission android:name="android.hardware.microphone" android:required="true"/>
<uses-permission android:name="android.hardware.sip.voip" android:required="true" />
<uses-permission android:name="android.hardware.telephony" android:required="false" />
<application ...
<receiver android:name=".sip.calling.IncomingCallReceiver" android:label="Call Receiver"/>
<activity
android:name=".sip.calling.Call"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="uk.co.tbw.MainActivity"/>
</activity>
</application>
`
答案 0 :(得分:0)
您使用什么库进行SIP信令?
在某些图书馆中,您必须在建立时将麦克风和扬声器分配给通话。