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 aRecordingdatabase row, back up and MD5-verify the source media file, transcode it to.wmaviaMediaToolkit/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 theRecordingentity itself — onlyAudioImportStatusstate 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.Servicesthat are free of persistence or transport concerns. - Support a "degraded mode" construction path (
AudioVideoService(IUnitOfWork uow)) that limits a consumer to theHasMedia(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 entitiesRecordingandAudioImportStatusand theirClassMap<T>mappings (RecordingMap,AudioImportStatusMap), consumed throughIUnitOfWork/IRepository<T>supplied bySAIF.Framework.Data.NHibernate. - Service/orchestration layer (
SAIF.Services.Utilities.AudioVideo) —AudioVideoServiceis the single public entry point (IAudioVideoService) coordinating validation, persistence, file handling, and vendor deletion;AudioVideoValidatorenforces request validation rules;ImportStatusManagerownsAudioImportStatusstate;CallRecordingExtensionscomputes description/discoverability values. - Vendor adapter layer (
SAIF.Services.ClientProxies.ThirdParty) —CallRecordingSystemdelegates toCallRexServiceProxy(on-demand recording/user-list/recording-metadata SOAP operations) andCallRexStateServiceProxy(duplex real-time agent-state feed viaAgentStateCallback). No other class in the library talks to CallRex directly. - Framework dependencies —
SAIF.Framework.CoresuppliesIEnvironmentService,ILogService,IUnitOfWork,IRepository<T>;SAIF.Framework.Data.NHibernatesupplies the concrete NHibernate unit-of-work/repository stack;SAIF.Framework.CommonsuppliesEntityBase<T>,Enforce,SaifValidationException,IConsoleLogService, and extension methods (GetMD5Hash,GetErrorLogFormattedException).
Interaction model¶
- An external caller (outside this library) invokes
IAudioVideoService.ImportRecording,GetRecordingInfo,InvalidateRecording,CancelImport, orHasMediaonAudioVideoService. AudioVideoServicevalidates inboundImportAudioRequestinstances viaAudioVideoValidator(FluentValidation) before performing any database, file-system, or vendor-system action.- Database access flows through constructor-injected
IUnitOfWork/IRepository<Recording>/IRepository<AudioImportStatus>fromSAIF.Framework.Data.NHibernate— there is no intermediate business-object/DAO abstraction beyond the repository itself*. - File-system side effects (backup copy, MD5 integrity check,
ffmpegtranscode) are performed directly byAudioVideoServiceagainst a path resolved fromIEnvironmentService.GetConfigSetting("AudioImportService.callRexMediaOutputPath"). - Vendor-system interaction is always routed through
IRecordingSystem/CallRecordingSystem, which in turn callsCallRexServiceProxy(synchronous SOAP operations, NTLM-authenticatedBasicHttpsBinding, plus hardcoded SOAP-header credentials) orCallRexStateServiceProxy(duplexWSDualHttpBindingreal-time feed with no transport/message security). - Real-time call-state updates arrive asynchronously through the
AgentStateCallbackduplex WCF callback contract and are re-raised to the library's own caller as theOnCallStateChangedevent. - Import status is persisted/queried independently of the
Recordingrow viaImportStatusManager, soAudioImportStatusandRecordinglifecycles are not transactionally coupled to each other beyond the explicit rollback performed in theImportRecordingerror-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<T><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 toSAIF.Framework.Core,SAIF.Framework.Data.NHibernate, orSAIF.Framework.Common. - All vendor-system communication is constrained to the
SAIF.Services.ClientProxies.ThirdPartynamespace; 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 toHasMedia(long)only — every other method throwsNotImplementedExceptionin 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
IUnitOfWorkimplementation, its session strategy, and its Oracle/SQL Server configuration factory are resolved entirely insideSAIF.Framework.Data.NHibernateand/or the hosting application's DI composition root — this library only depends on theIUnitOfWork/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'sPipelines\folder builds or packsSAIF.Application.Services.AudioVideo.csprojor references either nuspec — whether packaging happens via a pipeline defined outside this repository is unknown.** CallRexServiceProxyembeds a service-account credential (_userId = "AI",_pwd = "AudioImporter") as plain string literals rather than resolving it viaIEnvironmentService.GetSecureConfigSetting— a design constraint of the current vendor-authentication approach rather than an environment-variance setting.
Related documentation¶
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.csprojApplication\SAIF.Application.Services.AudioVideo\packages.configApplication\SAIF.Application.Services.AudioVideo\app.configApplication\SAIF.Application.Services.AudioVideo\Core\Services\IAudioVideoService.csApplication\SAIF.Application.Services.AudioVideo\Core\Contracts\AudioVideo\IRecordingSystem.csApplication\SAIF.Application.Services.AudioVideo\Core\Contracts\AudioVideo\IImportStatusManager.csApplication\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\AudioVideoService.csApplication\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\AudioVideoValidator.csApplication\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\ImportStatusManager.csApplication\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\CallRecordingExtensions.csApplication\SAIF.Application.Services.AudioVideo\Services\Utilities\AudioVideo\RecordingSystem.csApplication\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\CallRexServiceProxy.csApplication\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\CallRexStateServiceProxy.csApplication\SAIF.Application.Services.AudioVideo\Services\ClientProxies\ThirdParty\AgentStateCallback.csApplication\SAIF.Application.Services.AudioVideo\Data\Mappings\AudioImportStatusMap.csApplication\SAIF.Application.Services.AudioVideo\Data\Mappings\RecordingMap.csnuspec\SAIF.Apps\SAIF.Application.Services.AudioVideo.nuspecnuspec\SAIF.Apps\SAIF.Application.Services.AudioVideo.32.nuspec