---
title: SAIF.Application.Services.AudioVideo architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Application.Services.AudioVideo
reference_type: package
---

# SAIF.Application.Services.AudioVideo architecture

`SAIF.Application.Services.AudioVideo` is a single-assembly Framework4 component library that orchestrates the import, invalidation, and cancellation of call recordings from the third-party CallRex call-recording appliance into SAIF, backed by an NHibernate-mapped persistence layer and a set of WCF client proxies that isolate all vendor-system interaction behind a single adapter boundary.

## Responsibilities
- Orchestrate the end-to-end call-recording import workflow (`AudioVideoService.ImportRecording`): validate the request, create or reuse a `Recording` database row, back up and MD5-verify the source media file, transcode it to `.wma` via `MediaToolkit`/`ffmpeg.exe`, verify the destination file, delete the source recording from CallRex, and mark import status complete.
- Track per-recording import status (`ImportStatusManager`/`IImportStatusManager`) as a distinct concern from the `Recording` entity itself — only `AudioImportStatus` state passes through the status manager.
- Provide a vendor-integration adapter (`CallRecordingSystem`/`IRecordingSystem`) that hides two WCF proxy classes (`CallRexServiceProxy`, `CallRexStateServiceProxy`) behind a single interface for on-demand recording operations and a real-time duplex agent-state feed.
- Expose contracts (DTOs, enums, service interfaces) in `SAIF.Core.Contracts.AudioVideo`/`SAIF.Core.Services` that are free of persistence or transport concerns.
- Support a "degraded mode" construction path (`AudioVideoService(IUnitOfWork uow)`) that limits a consumer to the `HasMedia(long)` query only, for callers that need existence-checking without the full service graph*.

## Component boundaries
- **Contracts layer** (`SAIF.Core.Contracts.AudioVideo`, `SAIF.Core.Services`) — pure DTOs, enums, and interfaces (`IAudioVideoService`, `IRecordingSystem`, `IImportStatusManager`); no dependency on persistence or transport.
- **Persistence layer** (`SAIF.Data.Model.AudioVideo`, `SAIF.Data.NHibernate.Mappings.AudioVideo`) — NHibernate entities `Recording` and `AudioImportStatus` and their `ClassMap<T>` mappings (`RecordingMap`, `AudioImportStatusMap`), consumed through `IUnitOfWork`/`IRepository<T>` supplied by `SAIF.Framework.Data.NHibernate`.
- **Service/orchestration layer** (`SAIF.Services.Utilities.AudioVideo`) — `AudioVideoService` is the single public entry point (`IAudioVideoService`) coordinating validation, persistence, file handling, and vendor deletion; `AudioVideoValidator` enforces request validation rules; `ImportStatusManager` owns `AudioImportStatus` state; `CallRecordingExtensions` computes description/discoverability values.
- **Vendor adapter layer** (`SAIF.Services.ClientProxies.ThirdParty`) — `CallRecordingSystem` delegates to `CallRexServiceProxy` (on-demand recording/user-list/recording-metadata SOAP operations) and `CallRexStateServiceProxy` (duplex real-time agent-state feed via `AgentStateCallback`). No other class in the library talks to CallRex directly.
- **Framework dependencies** — `SAIF.Framework.Core` supplies `IEnvironmentService`, `ILogService`, `IUnitOfWork`, `IRepository<T>`; `SAIF.Framework.Data.NHibernate` supplies the concrete NHibernate unit-of-work/repository stack; `SAIF.Framework.Common` supplies `EntityBase<T>`, `Enforce`, `SaifValidationException`, `IConsoleLogService`, and extension methods (`GetMD5Hash`, `GetErrorLogFormattedException`).

## Interaction model
- An external caller (outside this library) invokes `IAudioVideoService.ImportRecording`, `GetRecordingInfo`, `InvalidateRecording`, `CancelImport`, or `HasMedia` on `AudioVideoService`.
- `AudioVideoService` validates inbound `ImportAudioRequest` instances via `AudioVideoValidator` (FluentValidation) before performing any database, file-system, or vendor-system action.
- Database access flows through constructor-injected `IUnitOfWork`/`IRepository<Recording>`/`IRepository<AudioImportStatus>` from `SAIF.Framework.Data.NHibernate` — there is no intermediate business-object/DAO abstraction beyond the repository itself*.
- File-system side effects (backup copy, MD5 integrity check, `ffmpeg` transcode) are performed directly by `AudioVideoService` against a path resolved from `IEnvironmentService.GetConfigSetting("AudioImportService.callRexMediaOutputPath")`.
- Vendor-system interaction is always routed through `IRecordingSystem`/`CallRecordingSystem`, which in turn calls `CallRexServiceProxy` (synchronous SOAP operations, NTLM-authenticated `BasicHttpsBinding`, plus hardcoded SOAP-header credentials) or `CallRexStateServiceProxy` (duplex `WSDualHttpBinding` real-time feed with no transport/message security).
- Real-time call-state updates arrive asynchronously through the `AgentStateCallback` duplex WCF callback contract and are re-raised to the library's own caller as the `OnCallStateChanged` event.
- Import status is persisted/queried independently of the `Recording` row via `ImportStatusManager`, so `AudioImportStatus` and `Recording` lifecycles are not transactionally coupled to each other beyond the explicit rollback performed in the `ImportRecording` error-handling branch.

## Architecture diagram
The following diagram shows the library's internal layering and its external system/dependency boundaries.

```mermaid
flowchart TD
	Caller["External caller<br>(outside this library)"] --> AVS["AudioVideoService<br>(IAudioVideoService)"]
	AVS --> Validator["AudioVideoValidator<br>(FluentValidation)"]
	AVS --> ISM["ImportStatusManager<br>(IImportStatusManager)"]
	AVS --> Repo["IUnitOfWork / IRepository&lt;T&gt;<br>(SAIF.Framework.Data.NHibernate)"]
	AVS --> FS["File system<br>(backup, MD5, ffmpeg transcode)"]
	AVS --> RS["CallRecordingSystem<br>(IRecordingSystem)"]
	ISM --> Repo
	RS --> Proxy1["CallRexServiceProxy<br>(SOAP, on-demand)"]
	RS --> Proxy2["CallRexStateServiceProxy<br>(duplex, real-time)"]
	Proxy1 --> CallRex["CallRex vendor system"]
	Proxy2 --> CallRex
	Repo --> Env["IEnvironmentService<br>(SAIF.Framework.Core)"]
	AVS --> Env
	Repo --> DB[("Oracle database<br>(RECORDING, audio_import_status)")]
```

## Sequence diagram
The following diagram shows the primary `ImportRecording` request/response sequence.

```mermaid
sequenceDiagram
	participant Caller as External caller
	participant AVS as AudioVideoService
	participant Val as AudioVideoValidator
	participant Repo as IUnitOfWork/IRepository
	participant FS as File system / ffmpeg
	participant RS as CallRecordingSystem
	participant Vendor as CallRex vendor system
	Caller->>AVS: ImportRecording(ImportAudioRequest)
	AVS->>Val: Validate(request)
	Val-->>AVS: ValidationResult
	AVS->>Repo: Query/Add Recording
	Repo-->>AVS: Recording row
	AVS->>FS: Backup + MD5 verify + transcode
	FS-->>AVS: Success/failure
	AVS->>RS: DeleteRecording(callRecordingId)
	RS->>Vendor: DeleteRecording (SOAP)
	Vendor-->>RS: Result
	RS-->>AVS: Result
	AVS->>Repo: Mark AudioImportStatus completed
	AVS-->>Caller: RecordingInfo
```

## Design constraints
- The library targets .NET Framework 4.6.1 and is consumed as compiled NuGet packages (`packages.config`/`<Reference>`), not `<ProjectReference>`, for all internal SAIF dependencies — there is no compile-time project coupling to `SAIF.Framework.Core`, `SAIF.Framework.Data.NHibernate`, or `SAIF.Framework.Common`.
- All vendor-system communication is constrained to the `SAIF.Services.ClientProxies.ThirdParty` namespace; no other layer is permitted to reference the generated WCF service-reference proxies directly.
- The degraded-mode constructor (`AudioVideoService(IUnitOfWork uow)`) intentionally restricts the service surface to `HasMedia(long)` only — every other method throws `NotImplementedException` in that mode, reflecting a single external consumer's minimal dependency need*.
- Database access is constrained to LINQ-to-NHibernate expressions against `IRepository<TEntity>.Query()`; no raw/inline SQL or stored-procedure calls exist in this library's own code.
- The concrete `IUnitOfWork` implementation, its session strategy, and its Oracle/SQL Server configuration factory are resolved entirely inside `SAIF.Framework.Data.NHibernate` and/or the hosting application's DI composition root — this library only depends on the `IUnitOfWork`/`IRepository<T>` abstractions.**
- Packaging status is uncertain: standalone nuspec files exist for this library (`nuspec\SAIF.Apps\SAIF.Application.Services.AudioVideo.nuspec`, `.32.nuspec`) but no pipeline YAML in this repository's `Pipelines\` folder builds or packs `SAIF.Application.Services.AudioVideo.csproj` or references either nuspec — whether packaging happens via a pipeline defined outside this repository is unknown.**
- `CallRexServiceProxy` embeds a service-account credential (`_userId = "AI"`, `_pwd = "AudioImporter"`) as plain string literals rather than resolving it via `IEnvironmentService.GetSecureConfigSetting` — a design constraint of the current vendor-authentication approach rather than an environment-variance setting.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts. Statements marked with `**` could not be confirmed; treat
> as unknown until verified.

## Sources
- `Application\SAIF.Application.Services.AudioVideo\SAIF.Application.Services.AudioVideo.csproj`
- `Application\SAIF.Application.Services.AudioVideo\packages.config`
- `Application\SAIF.Application.Services.AudioVideo\app.config`
- `Application\SAIF.Application.Services.AudioVideo\Core\Services\IAudioVideoService.cs`
- `Application\SAIF.Application.Services.AudioVideo\Core\Contracts\AudioVideo\IRecordingSystem.cs`
- `Application\SAIF.Application.Services.AudioVideo\Core\Contracts\AudioVideo\IImportStatusManager.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\AudioVideoService.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\AudioVideoValidator.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\ImportStatusManager.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\CallRecordingExtensions.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\RecordingSystem.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\CallRexServiceProxy.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\CallRexStateServiceProxy.cs`
- `Application\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\AgentStateCallback.cs`
- `Application\SAIF.Application.Services.AudioVideo\Data\Mappings\AudioImportStatusMap.cs`
- `Application\SAIF.Application.Services.AudioVideo\Data\Mappings\RecordingMap.cs`
- `nuspec\SAIF.Apps\SAIF.Application.Services.AudioVideo.nuspec`
- `nuspec\SAIF.Apps\SAIF.Application.Services.AudioVideo.32.nuspec`
