@qusaieilouti99/call-manager 0.1.66 → 0.1.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,6 @@ import android.graphics.Color
13
13
  import android.media.AudioAttributes
14
14
  import android.media.AudioDeviceCallback
15
15
  import android.media.AudioDeviceInfo
16
- import android.media.AudioFocusRequest
17
16
  import android.media.AudioManager
18
17
  import android.media.MediaPlayer
19
18
  import android.media.RingtoneManager
@@ -51,13 +50,11 @@ object CallEngine {
51
50
  private val isInitialized = AtomicBoolean(false)
52
51
  private val initializationLock = Any()
53
52
 
54
- // Audio & Media - SIMPLIFIED
53
+ // Simplified Audio & Media Management (NO MANUAL AUDIO FOCUS)
55
54
  private var ringtone: android.media.Ringtone? = null
56
55
  private var ringbackPlayer: MediaPlayer? = null
57
56
  private var audioManager: AudioManager? = null
58
57
  private var wakeLock: PowerManager.WakeLock? = null
59
- private var audioFocusRequest: AudioFocusRequest? = null
60
- private var hasAudioFocus: Boolean = false
61
58
 
62
59
  // Call State Management
63
60
  private val activeCalls = ConcurrentHashMap<String, CallInfo>()
@@ -67,7 +64,7 @@ object CallEngine {
67
64
  private var currentCallId: String? = null
68
65
  private var canMakeMultipleCalls: Boolean = false
69
66
 
70
- // Audio State Tracking - SIMPLIFIED
67
+ // Audio State Tracking
71
68
  private var lastAudioRoutesInfo: AudioRoutesInfo? = null
72
69
 
73
70
  // Lock Screen Bypass
@@ -129,92 +126,6 @@ object CallEngine {
129
126
  }
130
127
  }
131
128
 
132
- // --- SIMPLIFIED Audio Focus Management ---
133
- private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
134
- Log.d(TAG, "Audio focus changed: $focusChange")
135
- when (focusChange) {
136
- AudioManager.AUDIOFOCUS_LOSS -> {
137
- // Only hold calls on PERMANENT audio focus loss (like system calls)
138
- Log.d(TAG, "Permanent audio focus loss - holding calls")
139
- hasAudioFocus = false
140
- holdAllActiveCalls(heldBySystem = true)
141
- }
142
- AudioManager.AUDIOFOCUS_GAIN -> {
143
- Log.d(TAG, "Audio focus gained - resuming held calls")
144
- hasAudioFocus = true
145
- Handler(Looper.getMainLooper()).postDelayed({
146
- resumeSystemHeldCalls()
147
- }, 1000)
148
- }
149
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT,
150
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
151
- // Don't hold calls for transient losses - just note we lost focus
152
- Log.d(TAG, "Transient audio focus loss - keeping calls active")
153
- hasAudioFocus = false
154
- }
155
- }
156
- }
157
-
158
- private fun requestAudioFocus(): Boolean {
159
- val context = requireContext()
160
- audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
161
-
162
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
163
- if (audioFocusRequest == null) {
164
- audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
165
- .setAudioAttributes(
166
- AudioAttributes.Builder()
167
- .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
168
- .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
169
- .build()
170
- )
171
- .setOnAudioFocusChangeListener(audioFocusChangeListener)
172
- .setAcceptsDelayedFocusGain(true)
173
- .build()
174
- }
175
- val result = audioManager?.requestAudioFocus(audioFocusRequest!!)
176
- hasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
177
- Log.d(TAG, "Audio focus request result: $result (granted: $hasAudioFocus)")
178
- hasAudioFocus
179
- } else {
180
- @Suppress("DEPRECATION")
181
- val result = audioManager?.requestAudioFocus(
182
- audioFocusChangeListener,
183
- AudioManager.STREAM_VOICE_CALL,
184
- AudioManager.AUDIOFOCUS_GAIN
185
- )
186
- hasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
187
- hasAudioFocus
188
- }
189
- }
190
-
191
- private fun abandonAudioFocus() {
192
- audioManager?.let { am ->
193
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
194
- audioFocusRequest?.let { request ->
195
- am.abandonAudioFocusRequest(request)
196
- }
197
- } else {
198
- @Suppress("DEPRECATION")
199
- am.abandonAudioFocus(audioFocusChangeListener)
200
- }
201
- }
202
- hasAudioFocus = false
203
- Log.d(TAG, "Audio focus abandoned")
204
- }
205
-
206
- private fun holdAllActiveCalls(heldBySystem: Boolean) {
207
- activeCalls.values.filter { it.state == CallState.ACTIVE }.forEach { call ->
208
- holdCallInternal(call.callId, heldBySystem = heldBySystem)
209
- }
210
- }
211
-
212
- private fun resumeSystemHeldCalls() {
213
- activeCalls.values.filter { it.state == CallState.HELD && it.wasHeldBySystem }.forEach { call ->
214
- unholdCallInternal(call.callId, resumedBySystem = true)
215
- }
216
- }
217
-
218
129
  // --- Lock Screen Bypass Management ---
219
130
  fun registerLockScreenBypassCallback(callback: LockScreenBypassCallback) {
220
131
  lockScreenBypassCallbacks.add(callback)
@@ -373,6 +284,9 @@ object CallEngine {
373
284
  currentCallId = callId
374
285
  Log.d(TAG, "Call $callId added to activeCalls. State: DIALING")
375
286
 
287
+ // ONLY set audio mode - let system handle audio focus for self-managed calls
288
+ setAudioMode()
289
+
376
290
  registerPhoneAccount()
377
291
  val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
378
292
  val phoneAccountHandle = getPhoneAccountHandle()
@@ -396,8 +310,7 @@ object CallEngine {
396
310
  telecomManager.placeCall(addressUri, extras)
397
311
  startForegroundService()
398
312
 
399
- // SIMPLIFIED: Request audio focus and start ringback
400
- requestAudioFocus()
313
+ // Start ringback (system will handle audio focus)
401
314
  startRingback()
402
315
 
403
316
  bringAppToForeground()
@@ -441,7 +354,7 @@ object CallEngine {
441
354
  Log.d(TAG, "Call $callId started as ACTIVE")
442
355
 
443
356
  registerPhoneAccount()
444
- requestAudioFocus()
357
+ setAudioMode()
445
358
  bringAppToForeground()
446
359
  startForegroundService()
447
360
  keepScreenAwake(true)
@@ -452,7 +365,7 @@ object CallEngine {
452
365
  emitOutgoingCallAnsweredWithMetadata(callId)
453
366
  }
454
367
 
455
- // --- Call Answer Management - SIMPLIFIED ---
368
+ // --- Call Answer Management (SIMPLIFIED - NO MANUAL AUDIO FOCUS) ---
456
369
  fun callAnsweredFromJS(callId: String) {
457
370
  Log.d(TAG, "callAnsweredFromJS: $callId - remote party answered")
458
371
  coreCallAnswered(callId, isLocalAnswer = false)
@@ -463,7 +376,7 @@ object CallEngine {
463
376
  coreCallAnswered(callId, isLocalAnswer = true)
464
377
  }
465
378
 
466
- // SIMPLIFIED: Always succeed call answer, handle audio focus gracefully
379
+ // SIMPLIFIED: Let system handle audio focus for self-managed calls
467
380
  private fun coreCallAnswered(callId: String, isLocalAnswer: Boolean) {
468
381
  Log.d(TAG, "coreCallAnswered: $callId, isLocalAnswer: $isLocalAnswer")
469
382
 
@@ -473,19 +386,20 @@ object CallEngine {
473
386
  return
474
387
  }
475
388
 
476
- // ALWAYS set call to ACTIVE - don't fail due to audio focus
389
+ // Set audio mode and let system handle audio focus
390
+ setAudioMode()
391
+
392
+ // Set call to ACTIVE
477
393
  activeCalls[callId] = callInfo.copy(state = CallState.ACTIVE)
478
394
  currentCallId = callId
479
- Log.d(TAG, "Call $callId set to ACTIVE state")
395
+ Log.d(TAG, "Call $callId set to ACTIVE state (system manages audio focus)")
480
396
 
481
397
  // Clean up media and UI
482
398
  stopRingtone()
483
399
  stopRingback()
484
400
  cancelIncomingCallUI()
485
401
 
486
- // Request audio focus (but don't fail if not granted)
487
- requestAudioFocus()
488
-
402
+ // Handle multiple calls
489
403
  if (!canMakeMultipleCalls) {
490
404
  activeCalls.filter { it.key != callId }.values.forEach { otherCall ->
491
405
  if (otherCall.state == CallState.ACTIVE) {
@@ -497,10 +411,9 @@ object CallEngine {
497
411
  bringAppToForeground()
498
412
  startForegroundService()
499
413
  keepScreenAwake(true)
500
- setAudioMode()
501
414
  updateLockScreenBypass()
502
415
 
503
- // Always emit events based on call direction
416
+ // Emit events based on call direction
504
417
  if (isLocalAnswer) {
505
418
  emitCallAnsweredWithMetadata(callId)
506
419
  } else {
@@ -716,7 +629,7 @@ object CallEngine {
716
629
  })
717
630
  }
718
631
 
719
- // --- Audio Management ---
632
+ // --- Audio Management (SIMPLIFIED - NO MANUAL AUDIO FOCUS) ---
720
633
  fun getAudioDevices(): AudioRoutesInfo {
721
634
  val context = requireContext()
722
635
  audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager ?: run {
@@ -822,6 +735,7 @@ object CallEngine {
822
735
 
823
736
  private fun setAudioMode() {
824
737
  audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION
738
+ Log.d(TAG, "Audio mode set to MODE_IN_COMMUNICATION (system handles audio focus)")
825
739
  }
826
740
 
827
741
  private fun resetAudioMode() {
@@ -830,7 +744,7 @@ object CallEngine {
830
744
  audioManager?.stopBluetoothSco()
831
745
  audioManager?.isBluetoothScoOn = false
832
746
  audioManager?.isSpeakerphoneOn = false
833
- abandonAudioFocus()
747
+ Log.d(TAG, "Audio mode reset to MODE_NORMAL")
834
748
  }
835
749
  }
836
750
 
@@ -1028,7 +942,7 @@ object CallEngine {
1028
942
  stopRingtone()
1029
943
  }
1030
944
 
1031
- // --- Service Management - SIMPLIFIED ---
945
+ // --- Service Management ---
1032
946
  private fun startForegroundService() {
1033
947
  val context = requireContext()
1034
948
  val currentCall = activeCalls.values.find {
@@ -1161,7 +1075,7 @@ object CallEngine {
1161
1075
  }
1162
1076
  }
1163
1077
 
1164
- // --- Cleanup - SIMPLIFIED ---
1078
+ // --- Cleanup ---
1165
1079
  private fun cleanup() {
1166
1080
  Log.d(TAG, "Performing cleanup")
1167
1081
  stopForegroundService()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qusaieilouti99/call-manager",
3
- "version": "0.1.66",
3
+ "version": "0.1.68",
4
4
  "description": "Call manager",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",