package com.dmc.callcrm import android.os.Build import java.util.Locale /** * Central config for where the app sends data. * * BASE_URL must end with a trailing slash and point at the /api/ folder * on your server (the PHP backend in this repo). * * APP_SECRET must match APP_SECRET in backend/config.php (leave "" to disable). */ object ApiConfig { const val BASE_URL = "https://callcrm.dholerametrocityoffer.com/dmc-call-crm/backend/api/" const val APP_SECRET = "" // set the same value on the server if you enable it // How often the background worker force-syncs, in minutes (min allowed by WorkManager is 15). const val SYNC_INTERVAL_MIN = 15L // How many days of history to read on the very first sync (call logs AND // recordings) — without this, a phone with years of call history would // try to sync everything at once, which is slow. Wired up in Syncer.kt // and RecordingUploader.kt. const val FIRST_SYNC_DAYS = 120 // ---- Call recording ---- // "oem" = only harvest files made by the phone's built-in recorder (best quality, both sides) // "mic" = record via microphone during the call (works on Android 10-13 without an OEM recorder) // "both" = do both (may create two recordings per call on devices that have an OEM recorder) // // This used to be a single hardcoded value for every device, which is wrong for a mixed-brand // office: "oem" only gets real audio on brands where we've *confirmed* the native recorder (or // a dialer swap like Google Phone) actually writes a real, non-silent, both-sides file. // - Samsung: confirmed working (native recorder, standard folder). // - Xiaomi/Redmi/POCO (MIUI): confirmed working (native recorder writes real .mp3 files // to MIUI/sound_recorder/call_rec — verified against real device files of varying, // non-trivial sizes, not silent/empty placeholders). // - Vivo: set to OEM-only per request. IMPORTANT — this was previously in "both" mode // specifically because Vivo's uploaded recordings (via Google Phone's region-gated // recorder) were confirmed SILENT. Switching to pure OEM harvest only fixes the sound // if the file being harvested now actually has audio (e.g. Vivo's own native dialer // recorder, not Google Phone's) — it does not add sound to a source that has none. // If uploads are still silent after this change, the problem is upstream of this app // (the recorder producing the file), not something this config can fix. // - Everyone else (Oppo, OnePlus, Realme, stock Android...): NOT confirmed. So for these // we use "both": mic capture (which we control end-to-end) as the reliable baseline, // plus opportunistic OEM harvesting in case the device's native recorder does turn out // to work — RecordingScanner already de-dupes by file path, so this never uploads the // same file twice; at worst a call has two recordings and you keep whichever has audio. // // Before adding a manufacturer to the confirmed set: install the app on a real device of that // brand, use the "Test mic recording" option (More tab) to confirm the mic path captures both // sides, and separately check the phone's Files app for a real, non-empty native recording // after a test call. Don't add a brand just because it *has* a recording toggle somewhere. private val OEM_CONFIRMED_MANUFACTURERS = setOf("samsung", "xiaomi", "redmi", "poco", "vivo") /** * Resolves "oem" / "mic" / "both" for the CURRENT device at runtime. See notes above. * Checks both MANUFACTURER (e.g. "Xiaomi") and BRAND (e.g. "POCO", "Redmi" ship as their * own brand on some regions/models even though MANUFACTURER often still reports "Xiaomi"). */ fun recordingMode(): String { val manufacturer = Build.MANUFACTURER?.lowercase(Locale.ROOT).orEmpty() val brand = Build.BRAND?.lowercase(Locale.ROOT).orEmpty() val confirmed = manufacturer in OEM_CONFIRMED_MANUFACTURERS || brand in OEM_CONFIRMED_MANUFACTURERS return if (confirmed) "oem" else "both" } // For mic mode: force speakerphone ON during the call so the CLIENT's voice is captured too. // Without this you mostly capture the employee's side (or nothing at all — several OEMs mute // the raw MIC input entirely during an active call unless audio is being routed through the // speaker). Intrusive (call is audible to anyone nearby) but necessary for two-way audio. const val AUTO_SPEAKER_DURING_CALL = true // Mic recording quality const val MIC_SAMPLE_RATE = 44100 const val MIC_BITRATE = 96000 /** URL the in-app player streams from for a given recording (see api/recording.php). */ fun recordingStreamUrl(recordingId: Long, apiToken: String): String = "$BASE_URL" + "recording.php?recording_id=$recordingId&api_token=$apiToken" }