我正在开发一个Android应用程序,该应用程序应接收Sip呼叫。 sip连接应始终建立,因此我为此使用了服务。
我遇到了一些问题:
P.S。我已经通过主要活动+接收器测试了sip连接,效果很好。问题始于服务+多个活动的实现
manifest.xml
<receiver android:name=".IncomingCallReceiver" android:enabled="true" />
<service android:name=".SipService" android:enabled="true" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
<uses-feature android:name="android.software.sip" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
MainActivity-在这里,我检查服务是否未运行,并启动它和SIP权限。
protected override void OnCreate(Bundle savedInstanceState)
{
///stuff
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.UseSip) != Permission.Granted ||
ContextCompat.CheckSelfPermission(this, Manifest.Permission.RecordAudio) != Permission.Granted ||
ContextCompat.CheckSelfPermission(this, Manifest.Permission.ProcessOutgoingCalls) != Permission.Granted)
ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.UseSip, Manifest.Permission.RecordAudio, Manifest.Permission.ProcessOutgoingCalls }, 0);
StartSipService();
}
private void StartSipService()
{
if (!IsServiceRunning(typeof(SipService)))
StartService(new Intent(this, typeof(SipService)));
}
//its deprecated ,but works for own services
private bool IsServiceRunning(Type cls)
{
var manager = (ActivityManager)GetSystemService(Context.ActivityService);
return manager.GetRunningServices(int.MaxValue).Any(service =>
service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName));
}
SipService-它应该注册sip +绑定了呼叫接受\拒绝
public class SipService : Service, ISipRegistrationListener
{
public IBinder Binder { get; private set; }
public SipManager SipManager;
public SipProfile SipProfile;
public IncomingCallReceiver CallReceiver;
public SipAudioCall AudioCall;
public override void OnCreate()
{
RegisterReceiver();
CreateSipProfile("login", "pass", "domain");
base.OnCreate();
}
public void RegisterReceiver()
{
var filter = new IntentFilter();
filter.AddAction("com.myapp.INCOMING_CALL");
CallReceiver = new IncomingCallReceiver();
RegisterReceiver(CallReceiver, filter);
}
public override IBinder OnBind(Intent intent)
{
Binder = new SipBinder(this);
return new SipBinder(this);
}
public void StartCall()
{
if (AudioCall == null) return;
AudioCall.AnswerCall(30);
AudioCall.StartAudio();
if (AudioCall.IsMuted) AudioCall.ToggleMute();
}
public void StopCall()
{
AudioCall?.Close();
}
public override void OnDestroy()
{
Binder = null;
CloseLocalSipProfile();
base.OnDestroy();
}
public void OnRegistering(string localProfileUri) { }
public void OnRegistrationDone(string localProfileUri, long expiryTime) { }
public void OnRegistrationFailed(string localProfileUri, SipErrorCodes errorCode, string errorMessage)
{
CloseLocalSipProfile();
}
private void CreateSipProfile(string username, string password, string domain)
{
if (SipManager == null)
SipManager = SipManager.NewInstance(this);
var builder = new SipProfile.Builder(username, domain);
builder.SetPassword(password);
SipProfile = builder.Build();
RegisterSipIncomСall();
}
private void RegisterSipIncomСall()
{
var intent = new Intent();
intent.SetAction("tattelecom.nateks.INCOMING_CALL");
var pendingIntent = PendingIntent.GetBroadcast(this, 0, intent,
(PendingIntentFlags)FillInFlags.Data);
SipManager?.Open(SipProfile, pendingIntent, null);
SipManager?.SetRegistrationListener(SipProfile.UriString, this);
}
public void CloseLocalSipProfile()
{
if (SipManager == null) return;
if (SipProfile != null)
SipManager.Close(SipProfile.UriString);
if (CallReceiver != null)
UnregisterReceiver(CallReceiver);
}
}
}
SipBinder
public class SipBinder : Binder
{
public SipService Service { get; private set; }
public SipBinder(SipService service)
{
Service = service;
}
public void StartCall()
{
Service.StartCall();
}
public void StopCall()
{
Service.StopCall();
}
}
SipServiceConnection
public class SipServiceConnection : Java.Lang.Object, IServiceConnection
{
private CallActivity _activityCall;
private AcceptanceActivity _activityAcceptance;
public bool IsConnected { get; private set; }
public SipBinder Binder { get; private set; }
public SipServiceConnection(CallActivity activity)
{
_activityCall= activity;
IsConnected = false;
Binder = null;
}
public SipServiceConnection(AcceptanceActivity activity)
{
_activityAcceptance= activity;
IsConnected = false;
Binder = null;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
Binder = service as SipBinder;
IsConnected = Binder != null;
}
public void OnServiceDisconnected(ComponentName name)
{
IsConnected = false;
Binder = null;
}
public void StartCall()
{
if (IsConnected) Binder?.StartCall();
}
public void StopCall()
{
if (IsConnected) Binder?.StopCall();
}
}
}
IncomingCallReceiver-应该将呼叫发送到服务并打开接受活动
public class IncomingCallReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
SipAudioCall incomingCall = null;
var listener = new SipAudioCall.Listener();
SipService service= (SipService)context;
incomingCall = service.SipManager.TakeAudioCall(intent, listener);
if (incomingCall.IsMuted) incomingCall.ToggleMute();
service.AudioCall = incomingCall;
var newIntent = new Intent(activity.ApplicationContext,typeof(AcceptanceActivity));
newIntent.AddFlags(ActivityFlags.NewTask);
service.StartActivity(newIntent );
}}}
AcceptanceActivity-绑定到服务,如果用户接受呼叫-打开呼叫活动。如果拒绝-service.closeCall
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
///stuff
if (_serviceConnection == null)
_serviceConnection = new SipServiceConnection(this);
Intent serviceToStart = new Intent(this, typeof(SipService));
BindService(serviceToStart, _serviceConnection, Bind.AutoCreate);
}
private void CloseOnClick(object sender, EventArgs e)
{
_serviceConnection?.StopCall();
Finish();
}
private void AnswerOnClick(object sender, EventArgs e)
{
var root = new Intent(this, typeof(CallActivity));
StartActivity(root);
Finish();
}
CallActivity-绑定到服务,开始音频呼叫并根据需要关闭呼叫
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if (_serviceConnection == null)
_serviceConnection = new SipServiceConnection(this);
Intent serviceToStart = new Intent(this, typeof(SipService));
BindService(serviceToStart, _serviceConnection, Bind.AutoCreate);
StartCall();
}
private void CloseOnClick(object sender, EventArgs e)
{
_serviceConnection?.StopCall();
}
private void StartCall()
{
_serviceConnection?.StartCall();
}
对于1.在启动服务时,您需要使用ForegroundService,而不是调用startService(),而是调用startForegroundService(),并在服务的onCreate中调用startForeground()
https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/services/foreground-services