Skip to content

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.

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.

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.

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