[Type: Refactoring]
[Scope: src/Tizen.Multimedia.Recorder]
[Priority: 🟡 Improvement]
[Lens: Coding Guidelines, Performance]
Observation
VideoRecorder.Capabilities.cs:74-91 의 GetSupportedVideoResolutions(CameraDevice) 는 정적 캐시 _frontResolutions / _rearResolutions 를 ??= 와 등가인 인라인 할당 으로 채웁니다. 락이 없어 동시에 두 스레드가 진입하면 LoadVideoResolutions 가 중복 호출되고, 그 안에서 new Camera(device) (네이티브 핸들 + 권한) 가 함께 두 번 생성됩니다.
Before
// src/Tizen.Multimedia.Recorder/Recorder/VideoRecorder.Capabilities.cs:74-91
private static IEnumerable<Size> _frontResolutions;
private static IEnumerable<Size> _rearResolutions;
public static IEnumerable<Size> GetSupportedVideoResolutions(CameraDevice device)
{
ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
if (device == CameraDevice.Front)
{
return _frontResolutions ?? (_frontResolutions = LoadVideoResolutions(CameraDevice.Front));
}
if (device == CameraDevice.Rear)
{
return _rearResolutions ?? (_rearResolutions = LoadVideoResolutions(CameraDevice.Rear));
}
Debug.Fail("No cache for " + device + ".");
return LoadVideoResolutions(device);
}
Problem
- 📐 Coding Guidelines (Thread Safety) — read → null check → assignment 이 비원자적이라 두 스레드가 동시에 진입하면
LoadVideoResolutions 가 중복 실행 됩니다. 그 안에서:
new Camera(device) ⇒ 네이티브 카메라 핸들 두 개 동시 오픈 시도
- Tizen 카메라 권한/리소스가 단일 점유형이라 두 번째 호출이
NotSupportedException / InvalidOperationException 으로 실패할 수 있음
- 첫 호출의 반환값이 캐시에 저장되지 않고 버려질 수 있음 (lost write)
- 🚀 Performance — 카메라 오픈 → 해상도 열거 → 카메라 닫기 사이클은 수십~수백 ms. 캐시가 무의미해지면 매 호출 비용 발생.
Proposed Improvement
Lazy<T> 로 변경 — 표준 thread-safe 캐시 패턴이며 동일 디렉터리 내 Recorder.Capabilities.cs 가 이미 같은 패턴 (Lazy<Capabilities>) 을 사용하고 있어 코드베이스 컨벤션에도 부합합니다.
After
private static readonly Lazy<IEnumerable<Size>> _frontResolutions =
new(() => LoadVideoResolutions(CameraDevice.Front));
private static readonly Lazy<IEnumerable<Size>> _rearResolutions =
new(() => LoadVideoResolutions(CameraDevice.Rear));
public static IEnumerable<Size> GetSupportedVideoResolutions(CameraDevice device)
{
ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
return device switch
{
CameraDevice.Front => _frontResolutions.Value,
CameraDevice.Rear => _rearResolutions.Value,
_ => LoadVideoResolutions(device), // unreachable post-ValidateEnum, kept for safety
};
}
Lazy<T> 의 기본값 LazyThreadSafetyMode.ExecutionAndPublication 이 동시 진입 시 한 번만 실행되도록 보장합니다.
Target Files
src/Tizen.Multimedia.Recorder/Recorder/VideoRecorder.Capabilities.cs (L29-L30, L74-L91)
Expected Impact (Quantitative Metrics)
- 중복
LoadVideoResolutions 호출: 가능 → 불가능 (정확성 픽스)
- 중복
new Camera(device) 네이티브 핸들 오픈: 가능 → 불가능 (자원 안전성 픽스)
- 데이터 레이스 윈도우: O(1) μs → 0
- 추가 할당:
Lazy<T> 인스턴스 2개, 클래스 로드 시 1회 (약 64 바이트 × 2)
- 코드 라인 증가: 0 (오히려 3 라인 감소 + switch expression 가독성 ↑)
- C# 12 switch expression 모더나이제이션 부가 효과
API Compatibility Check
- Public API signature change: 없음
- Behavior change: 없음 (성공 경로 결과는 동일; 동시 호출 시에만 정확성이 회복됨)
- Tizen API Level floor: 유지 (
Lazy<T> 는 .NET Framework 4.0+ 표준)
Impact Scope
- 호출 사이트: 1 메서드 (
GetSupportedVideoResolutions 자체) — public API 단일 진입점
- 외부 어셈블리 영향 없음 (구현 세부)
- 동일 디렉터리의
Recorder.Capabilities.cs:Capabilities = new Lazy<...>(...) 패턴과 일관화
[Type: Refactoring]
[Scope: src/Tizen.Multimedia.Recorder]
[Priority: 🟡 Improvement]
[Lens: Coding Guidelines, Performance]
Observation
VideoRecorder.Capabilities.cs:74-91의GetSupportedVideoResolutions(CameraDevice)는 정적 캐시_frontResolutions/_rearResolutions를??=와 등가인 인라인 할당 으로 채웁니다. 락이 없어 동시에 두 스레드가 진입하면LoadVideoResolutions가 중복 호출되고, 그 안에서new Camera(device)(네이티브 핸들 + 권한) 가 함께 두 번 생성됩니다.Before
Problem
LoadVideoResolutions가 중복 실행 됩니다. 그 안에서:new Camera(device)⇒ 네이티브 카메라 핸들 두 개 동시 오픈 시도NotSupportedException/InvalidOperationException으로 실패할 수 있음Proposed Improvement
Lazy<T>로 변경 — 표준 thread-safe 캐시 패턴이며 동일 디렉터리 내Recorder.Capabilities.cs가 이미 같은 패턴 (Lazy<Capabilities>) 을 사용하고 있어 코드베이스 컨벤션에도 부합합니다.After
Lazy<T>의 기본값LazyThreadSafetyMode.ExecutionAndPublication이 동시 진입 시 한 번만 실행되도록 보장합니다.Target Files
src/Tizen.Multimedia.Recorder/Recorder/VideoRecorder.Capabilities.cs(L29-L30, L74-L91)Expected Impact (Quantitative Metrics)
LoadVideoResolutions호출: 가능 → 불가능 (정확성 픽스)new Camera(device)네이티브 핸들 오픈: 가능 → 불가능 (자원 안전성 픽스)Lazy<T>인스턴스 2개, 클래스 로드 시 1회 (약 64 바이트 × 2)API Compatibility Check
Lazy<T>는 .NET Framework 4.0+ 표준)Impact Scope
GetSupportedVideoResolutions자체) — public API 단일 진입점Recorder.Capabilities.cs:Capabilities = new Lazy<...>(...)패턴과 일관화