BCR은 루팅된 장치 또는 맞춤형 펌웨어를 실행하는 장치를 위한 간단한 Android 통화 녹음 앱입니다. 활성화되면 방해가 되지 않고 백그라운드에서 들어오고 나가는 전화를 자동으로 녹음합니다.
이름에서 알 수 있듯이 BCR은 가능한 한 기본을 지향합니다. 필요한 업데이트가 새로운 Android 버전과의 호환성뿐이라면 프로젝트는 목표를 달성한 것입니다. 따라서 다음과 같이 잠재적으로 유용한 많은 기능은 구현되지 않습니다.
VOICE_CALL
오디오 소스를 지원하지 않는 장치에 대한 해결 방법(예: 마이크 + 스피커폰 사용)릴리스 페이지에서 최신 버전을 다운로드하세요. 디지털 서명을 확인하려면 디지털 서명 확인 섹션을 참조하세요.
BCR을 시스템 앱으로 설치합니다.
Magisk/KernelSU로 루팅된 장치의 경우 해당 애플리케이션 내에서 Zip을 Magisk/KernelSU 모듈로 플래시하기만 하면 됩니다.
.apk
를 추출하고 재부팅하기 전에 수동으로 설치하세요. 이는 앱 데이터 디렉터리가 생성되지 않아 BCR이 빈 화면으로 열리는 펌웨어의 버그를 해결하는 데 필요합니다.루팅되지 않은 사용자 정의 펌웨어의 경우 복구로 부팅하는 동안 zip을 플래시하세요.
READ_CALL_LOG
권한은 Android 10 이상에서 엄격하게 제한되어 있어 Android 설정을 통해서도 부여할 수 없습니다. 이 제한을 제거하려면 Android로 다시 재부팅한 후 adb를 통해 실행하세요. # If rooted, run inside of `su`:
CLASSPATH=/system/priv-app/com.chiller3.bcr/app-release.apk app_process / com.chiller3.bcr.standalone.RemoveHardRestrictionsKt
# If unrooted, install BCR as both a user app and a system app:
pm install /system/priv-app/com.chiller3.bcr/app-release.apk
system
파티션이 erofs
로 포맷된 경우 파일 시스템은 읽기 전용이므로 이 방법을 사용할 수 없습니다.644
권한과 u:object_r:system_file:s0
SELinux 라벨이 있는 경우 zip의 system/
폴더에서 파일을 수동으로 추출할 수도 있습니다.재부팅하고 BCR을 엽니다.
다른 통화 녹음기가 설치된 경우 해당 전화 통화 녹음 기능을 비활성화하십시오. 대부분의 장치에서는 두 개의 앱을 동시에 사용하여 전화 통화를 녹음할 수 없습니다. 그러나 BCR 기록 전화 통화 및 다른 앱 기록을 갖는 것은 괜찮습니다. VOIP 통화.
통화 녹음을 활성화하고 출력 디렉터리를 선택하세요.
출력 디렉터리를 선택하지 않거나 출력 디렉터리에 더 이상 액세스할 수 없는 경우 녹음 내용은 /sdcard/Android/data/com.chiller3.bcr/files
에 저장됩니다. Android 12 이상에서는 /sdcard/Android/data/
USB 또는 DocumentsUI(AOSP 내장 파일 관리자)를 통해서만 액세스할 수 있습니다.
통화 녹음을 처음 활성화하면 BCR은 마이크, 알림(Android 13+), 통화 기록, 연락처 및 전화 권한을 묻는 메시지를 표시합니다. 기본 통화 녹음 기능에는 마이크 및 알림 권한만 필요합니다. 추가 권한이 부여되면 출력 파일 이름에 더 많은 정보가 추가됩니다. 예를 들어 연락처 권한을 사용하면 연락처 이름을 파일 이름에 추가할 수 있습니다.
권한에 대한 자세한 내용은 아래 권한 섹션을 참조하세요.
향후 업데이트를 설치하려면 다음과 같은 몇 가지 방법이 있습니다.
.apk
는 zip에서 추출하여 직접 설치할 수도 있습니다. 이 방법을 사용하면 이전 버전이 시스템 앱으로 존재하고 새 버전이 시스템 앱에 대한 사용자 설치 업데이트로 존재합니다. BCR이 Android 펌웨어 이미지에 구워지면 이 방법이 더 편리합니다. 일부 장치에 사전 설치된 다이얼러 앱에 내장된 통화 녹음 기능과 달리 BCR은 통화가 녹음되고 있음을 상대방에게 알리지 않습니다. BCR은 통화 오디오 스트림에 어떤 종류의 오디오도 출력하지 않습니다.
BCR이 활성화되면 다이얼러의 내장 통화 녹음기를 전혀 사용하지 마십시오. 이를 사용하면 녹음이 모두 실패하거나 통화가 녹음되고 있음을 알리는 다이얼러와 같은 예기치 않은 동작이 발생할 가능성이 매우 높습니다.
양측의 동의가 필요한 관할권에 거주하는 경우 통화가 녹음되고 있음을 상대방에게 알릴 책임이 있습니다. 필요한 경우 자동 녹음 규칙을 사용하여 기본적으로 녹음을 삭제할 수 있습니다. 단, 통화 중에 녹음 내용을 보존하도록 선택하시면 상대방이 동의한 부분뿐만 아니라 통화 내용 전체가 녹음에 포함됩니다.
BCR은 직접 부팅을 인식합니다. 즉, 재부팅 후 장치가 처음 잠금 해제되기 전에 통화를 실행하고 녹음할 수 있습니다. 이 상태에서는 연락처 목록이나 통화 기록이 필요한 기능을 제외하고 대부분의 BCR 기능이 계속 작동합니다. 실제로 이는 다음을 의미합니다.
그러나 통화가 끝나기 전에 장치의 잠금이 해제되면 이러한 제한 사항이 적용되지 않습니다.
장치가 처음으로 잠금 해제되기 전에는 출력 디렉터리를 사용할 수 없습니다. 해당 상태에서 이루어진 녹음은 사용자가 접근할 수 없는 내부 디렉터리에 저장됩니다. 장치의 잠금이 해제되면 BCR은 파일을 출력 디렉터리로 이동합니다. 이 작업을 완료하는 데 몇 분 정도 걸릴 수 있습니다.
CAPTURE_AUDIO_OUTPUT
( 시스템 앱 권한에 의해 자동으로 부여됨 )CONTROL_INCALL_EXPERIENCE
( 시스템 앱 권한에 의해 자동으로 부여됨 )RECORD_AUDIO
( 사용자가 부여해야 함 )FOREGROUND_SERVICE
, FOREGROUND_SERVICE_MICROPHONE
( 설치 시 자동으로 부여됨 )POST_NOTIFICATIONS
( Android 13 이상 사용자가 승인해야 함 )READ_CALL_LOG
( 선택사항 )READ_CONTACTS
( 선택사항 )RECEIVE_BOOT_COMPLETED
, FOREGROUND_SERVICE_SPECIAL_USE
( 설치 시 자동으로 부여됨 )READ_PHONE_STATE
( 선택사항 )REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
( 선택사항 )VIBRATE
( 설치 시 자동으로 부여됨 ) INTERNET
은 목록에 없습니다 . BCR은 네트워크에 액세스하지 않으며 앞으로도 절대 액세스하지 않습니다. BCR은 녹음이 완료될 때 표시되는 알림에서 사용자가 명시적으로 Open
또는 Share
버튼을 탭하는 경우를 제외하고는 다른 앱과도 통신하지 않습니다. 이 시나리오에서 대상 앱에는 해당 단일 녹음에만 액세스할 수 있는 권한이 부여됩니다.
BCR은 Google Voice와 같은 통화 리디렉션 앱을 제한적으로 지원합니다. 재전송된 통화는 통화 재전송 서비스가 VOIP 대신 뒤에서 표준 전화 통화를 사용하는 경우에만 녹음될 수 있습니다.
일반 통화와 비교하여 재전송된 통화를 녹음할 때 다음과 같은 몇 가지 제한 사항이 있습니다.
All other calls
규칙과만 일치합니다.통화가 리디렉션될 때 다이얼러 앱 자체만 원래 전화번호를 인식하기 때문에 이러한 제한이 존재합니다. Android 전화 통신 시스템은 이를 인식하지 못합니다. BCR은 다이얼러가 통화 종료 시 항목을 추가할 때 시스템 통화 기록을 검색해야만 원래 전화 번호를 찾을 수 있습니다.
BCR은 녹음의 출력 파일 이름을 결정하는 데 사용되는 템플릿 사용자 정의를 지원합니다. 기본 템플릿은 다음과 같습니다.
{date}[_{direction}|][_sim{sim_slot}|][_{phone_number}|][_[{contact_name}|{caller_name}|{call_log_name}]|]
{var}
)는 변수를 참조하는 데 사용됩니다. 변수는 해당 변수가 나타내는 값으로 대체됩니다. 예를 들어, {phone_number}
실제 통화 전화번호로 대체됩니다.[{var}|default]
)가 사용됩니다. 예를 들어 [{contact_name}|{caller_name}|Unknown]
연락처에 번호가 있으면 연락처 이름을 삽입합니다. 그렇지 않으면 연락처 이름이나 발신자 ID가 모두 존재하지 않으면 발신자 ID 또는 Unknown
으로 대체됩니다. 빈 문자열로 대체하는 것도 완벽하게 유효합니다. 예를 들어, [{contact_name}|]
연락처 이름으로 평가되거나 아무것도 평가되지 않습니다.{date}
: 호출의 타임스탬프입니다. 기본 타임스탬프 형식은 가능한 한 명확하게 20230414_215701.088-0400
형식입니다. 사용자 정의 타임스탬프 형식은 {date:<format string>}
으로 지정할 수 있습니다. 예를 들어, {date:yyyy-MM-dd @ h.mm.ss a}
2023-04-14 @ 9.57.01 PM
생성합니다. 타임스탬프 형식화 문자의 전체 목록은 https://developer.android.com/reference/java/time/format/DateTimeFormatterBuilder#appendPattern(java.lang.String)에서 확인할 수 있습니다.{phone_number}{date}
하면 파일 보존이 비활성화되지만 {phone_number} ({date})
두 변수 사이에 일부 텍스트 (
가 있기 때문에 작동합니다.yyMMdd_HHmmss
HHmmss_yyMMdd
로 변경된 경우 이전 녹음 파일 이름의 타임스탬프가 잘못 구문 분석되어 삭제될 수 있습니다.{direction}
: [Android 10+만 해당] 1:1 통화의 경우 통화가 수신 통화인지 발신 통화인지에 따라 in
오거나 out
. 통화가 회의 통화인 경우 conference
대신 사용됩니다.{sim_slot}
: [Android 11+만 해당] 통화용 SIM 슬롯 번호입니다(1부터 계산). 이는 여러 SIM이 활성화되어 있고 BCR에 전화 권한이 부여된 다중 SIM 장치에 대해서만 정의됩니다.{sim_slot:always}
사용하세요.{phone_number}
: 통화에 대한 전화번호입니다. 비공개 통화의 경우 정의되지 않았습니다. 사용 가능한 서식 옵션:{phone_number:E.164}
: 기본값( {phone_number}
와 동일) 국제 E.164 형식( +<country code><subscriber>
)으로 형식화된 전화번호입니다.{phone_number:digits_only}
: 숫자만 포함된 전화번호입니다( +
또는 구분 기호 없음).{phone_number:formatted}
: 국가별 스타일을 사용하여 형식이 지정된 전화번호입니다.{caller_name}
: CNAP가 이동통신사로부터 제공한 발신자 ID입니다.{contact_name}
전화번호와 연결된 (첫 번째) 연락처의 이름입니다. 이는 BCR에 연락처 권한이 부여된 경우에만 정의됩니다.{call_log_name}
: 통화기록에 표시되는 이름입니다. 시스템 다이얼러가 역방향 조회를 수행하는 경우 여기에는 회사 이름과 같은 추가 정보가 포함될 수 있습니다. 이는 BCR에 통화 로그 읽기 권한이 부여된 경우에만 정의됩니다. 파일 이름 템플릿은 /
문자를 사용한 하위 디렉터리 지정을 지원합니다. 슬래시는 {date}
(예: {date:yyyy/MM/dd}
)를 포함하여 파일 이름 템플릿 내 어디에서나 허용됩니다. 그러나 다른 변수를 확장한 후에 나타나는 슬래시는 밑줄로 대체됩니다. 예를 들어 통화의 발신자 ID가 First/Last
이면 {caller_name}
First_Last
로 확장됩니다.
Android Storage Access Framework의 성능 저하로 인해 하위 디렉터리를 사용하면 일부 장치에서 녹화물 저장 속도가 크게 느려질 수 있습니다. SAF가 잘 구현된 Android 빌드에서는 이 시간이 몇 초 밖에 걸리지 않을 수 있습니다. 최악의 SAF 구현을 사용하는 OEM Android 빌드에서는 이 작업에 몇 분 정도 걸릴 수 있습니다. 지연은 출력 디렉터리의 파일 수에 비례합니다.
Write metadata file
옵션이 활성화된 경우 BCR은 BCR이 통화에 대해 알고 있는 모든 세부 정보와 녹음된 오디오에 대한 정보가 포함된 JSON 파일을 출력 디렉터리에 기록합니다. 파일 이름은 .json
확장자를 제외하고 오디오 파일과 동일합니다.
JSON 구조는 다음 예에 표시됩니다. timestamp_unix_ms
, timestamp
및 output.format.*
만 존재하도록 보장됩니다. 필드 값을 확인할 수 없는 경우(예: 오류가 발생하거나 필요한 권한이 거부된 경우) null
로 설정됩니다.
{
// The timestamp represented as milliseconds since the Unix epoch in UTC.
"timestamp_unix_ms" : 1689817988931 ,
// The timestamp represented as ISO8601 (+ offset) in the local time zone.
"timestamp" : "2023-07-19T21:53:08.931-04:00" ,
// The call direction ("in", "out", or "conference").
// [Android 10+ only]
"direction" : "in" ,
// The SIM slot used for the call.
// [Android 11+ only; requires the Phone permission]
"sim_slot" : 1 ,
// The name shown in the dialer's call log. This may include the business'
// name for dialers that perform reverse lookups.
// [Requires the Call Log permission]
"call_log_name" : "John Doe" ,
// Details about the other party or parties in the call. There will be
// multiple entries for conference calls.
"calls" : [
{
// The raw phone number as reported by Android. For outgoing calls,
// this is usually what the user typed. For incoming calls, this is
// usually E.164 formatted. This will be null for private calls.
"phone_number" : "+11234567890" ,
// The phone number formatted using the country-specific style. This
// will be null for private calls or if Android cannot determine the
// country.
"phone_number_formatted" : "+1 123-456-7890" ,
// The caller name/ID as reported by CNAP from the carrier.
"caller_name" : "John Doe" ,
// The contact name associated with the phone number.
// [Requires the Contacts permission]
"contact_name" : "John Doe"
}
] ,
// Details about the output file.
"output" : {
// Details about the output file format.
"format" : {
// The audio encoding format.
"type" : "OGG/Opus" ,
// The MIME type of the container format (eg. OGG).
"mime_type_container" : "audio/ogg" ,
// The MIME type of the raw audio stream (eg. Opus).
"mime_type_audio" : "audio/opus" ,
// The type of the parameter value below. Either "bitrate",
// "compression_level", or "none".
"parameter_type" : "bitrate" ,
// The encoder quality/size parameter.
"parameter" : 48000 ,
} ,
// Details about the recording and encoding process. If the recording
// process fails, this is set to null.
"recording" : {
// The total number of audio frames that BCR read from the audio
// device. This includes the periods of time when the recording was
// paused or on hold.
// (Number of frames == number of samples * channel count)
"frames_total" : 96000 ,
// The number of audio frames that were actually saved to the output
// file. This excludes the periods of time when the recording was
// paused or on hold.
// (Number of frames == number of samples * channel count)
"frames_encoded" : 48000 ,
// The number of samples per second of audio.
"sample_rate" : 48000 ,
// The number of channels in the audio. This is currently always 1
// because no device supports stereo call audio.
"channel_count" : 1 ,
// The total time in seconds that BCR read from the audio device.
// (Equal to: frames_total / sample_rate / channel_count)
"duration_secs_total" : 2.0 ,
// The time in seconds of audio actually saved to the output file.
// (Equal to: frames_encoded / sample_rate / channel_count)
"duration_secs_encoded" : 1.0 ,
// The size of the recording buffer in frames. This is the maximum
// number of audio frames read from the audio driver before it is
// passed to the audio encoder.
"buffer_frames" : 640 ,
// The number of buffer overruns. This is the number of times that
// the CPU or storage couldn't keep up while encoding the raw audio,
// resulting in skips (loss of audio).
"buffer_overruns" : 0 ,
// Whether the call was ever paused by the user.
"was_ever_paused" : false ,
// Whether the call was ever placed on hold (call waiting).
"was_ever_holding" : false
}
}
}
이 섹션에서는 BCR의 숨겨진 고급 기능을 설명합니다.
BCR에는 버전 번호를 길게 눌러 활성화하거나 비활성화할 수 있는 숨겨진 디버그 모드가 있습니다.
디버그 모드가 활성화되면 BCR은 통화 녹음이 완료된 후 출력 디렉터리에 로그 파일을 기록합니다. 오디오 파일과 같은 방식으로 이름이 지정됩니다. 로그 파일에는 adb logcat
표시하는 것과 동일한 메시지가 포함되어 있습니다. 단, BCR과 관련되지 않은 메시지는 필터링됩니다(BCR에는 해당 메시지에 액세스할 수 있는 권한이 없습니다).
BCR은 로그 파일 내에 민감한 정보를 절대 기록하지 않는 것을 목표로 합니다. 전화번호와 같은 현재 통화에 대한 정보는 대신 <phone number>
와 같은 자리 표시자로 대체됩니다. 그러나 다른 정보는 쉽게 수정할 수 없으므로 대신 잘립니다. 예를 들어, 파일 보존 기능이 오래된 파일을 정리할 때 20230101_010203.456+0000_out_1234567890_John_Doe.oga
와 같은 파일 이름은 20<...>ga
로 기록됩니다.
버그를 보고할 때 로그 파일을 포함시켜 주세요. 로그 파일은 무엇이 잘못되었는지 식별하는 데 매우 도움이 됩니다. (단, 로그파일을 다시 한번 확인하여 민감한 정보가 없는지 확인해주세요!)
BCR은 제대로 작동하기 위해 시스템 앱 권한에 크게 의존합니다. 이는 주로 다음 두 가지 권한 때문입니다.
CONTROL_INCALL_EXPERIENCE
이 권한을 사용하면 BCR이 웨어러블 컴패니언 앱, 자동차 UI 또는 기본 다이얼러가 되지 않고도 Android의 전화 통신 서비스가 BCR의 InCallService
에 바인딩될 수 있습니다. 연결되면 서비스는 통화 변경 이벤트(예: 벨이 울리는 상태에서 수신 전화)에 대한 콜백을 수신합니다. 이 방법은 READ_PHONE_STATE
권한을 사용하고 android.intent.action.PHONE_STATE
브로드캐스트에 의존하는 것보다 훨씬 더 안정적입니다.
이 방법에는 몇 가지 추가 이점이 있습니다. 전화 통신 서비스가 BCR의 InCallService
에 바인딩되는 방식으로 인해 서비스는 통화가 진행 중일 때 필요에 따라 포그라운드에 들어오고 나갈 수 있으며 Android 12+의 백그라운드 마이크 액세스 제한에 도달하지 않고도 오디오 스트림에 액세스할 수 있습니다. 또한 ACTION_BOOT_COMPLETED
방송 수신기에서 서비스를 수동으로 시작할 필요가 없으므로 초기 부팅 중 해당 방송 지연의 영향을 받지 않습니다.
CAPTURE_AUDIO_OUTPUT
이 권한은 VOICE_CALL
오디오 스트림을 녹음하는 데 사용됩니다. 이 스트림은 VOICE_DOWNLINK
및 VOICE_UPLINK
등의 다른 스트림과 함께 이 시스템 권한 없이는 액세스할 수 없습니다.
이 두 가지 권한을 통해 BCR은 전화 통화를 안정적으로 감지하고 통화 오디오 스트림에서 녹음할 수 있습니다. 녹음 프로세스에서는 PCM s16le 원시 오디오를 가져오고 Android의 내장 인코더를 사용하여 압축된 출력 파일을 생성합니다.
zip 파일과 포함된 APK는 모두 디지털 서명되어 있습니다. 참고 : zip 파일 서명 메커니즘은 버전 1.31부터 GPG에서 SSH로 전환되었습니다. 이전 버전의 서명을 확인하려면 버전 1.30의 README.md
참조하세요.
다운로드의 디지털 서명을 확인하려면 여기의 단계를 따르세요.
먼저 zip에서 apk를 추출한 후 다음을 실행합니다.
apksigner verify --print-certs system/priv-app/com.chiller3.bcr/app-release.apk
그런 다음 APK 서명 인증서의 SHA-256 다이제스트가 다음과 같은지 확인하세요.
d16f9b375df668c58ef4bb855eae959713d6d02e45f7f2c05ce2c27ae944f4f9
BCR은 Android Studio 또는 Gradle 명령줄을 사용하여 대부분의 다른 Android 앱처럼 구축할 수 있습니다.
APK를 빌드하려면 다음 안내를 따르세요.
./gradlew assembleDebug
Magisk 모듈 zip을 빌드하려면(필요한 경우 assembleDebug
작업을 자동으로 실행함):
./gradlew zipDebug
출력 파일은 app/build/distributions/debug/
에 기록됩니다. APK는 기본 자동 생성 디버그 키로 서명됩니다.
특정 서명 키를 사용하여 릴리스 빌드를 생성하려면 다음 환경 변수를 설정하세요.
export RELEASE_KEYSTORE=/path/to/keystore.jks
export RELEASE_KEY_ALIAS=alias_name
read -r -s RELEASE_KEYSTORE_PASSPHRASE
read -r -s RELEASE_KEY_PASSPHRASE
export RELEASE_KEYSTORE_PASSPHRASE
export RELEASE_KEY_PASSPHRASE
그런 다음 릴리스 zip을 빌드합니다.
./gradlew zipRelease
버그 수정 및 번역 풀 요청을 환영하며 매우 감사드립니다!
새로운 기능 구현에 관심이 있고 해당 기능이 BCR에 포함되기를 원한다면 먼저 문제를 열어 논의하십시오. 나는 BCR이 가능한 한 간단하고 유지 관리가 덜 되기를 원하므로 새로운 기능을 추가할 생각은 없지만 그렇지 않다고 확신할 수는 있습니다.
BCR은 GPLv3에 따라 라이센스가 부여됩니다. 전체 라이선스 텍스트를 보려면 LICENSE
참조하세요.