cal_core/device/
device.rs

1use crate::{AsrVendor, ConnectState, FlowState, Region, VoiceServer};
2use std::fmt::{Debug, Formatter};
3use std::sync::Arc;
4
5use cal_jambonz::dial::TranscribeDial;
6use cal_jambonz::listen::Listen;
7
8pub use crate::device::ani_router::ANIRouter;
9pub use crate::device::app_flow::AppFlow;
10pub use crate::device::client::Client;
11pub use crate::device::date_range_router::DateRangeRouter;
12pub use crate::device::day_of_week_router::DayOfWeekRouter;
13pub use crate::device::digit_router::DigitRouter;
14pub use crate::device::dnis_router::DNISRouter;
15pub use crate::device::email::Email;
16pub use crate::device::event::Event;
17pub use crate::device::hunt_group::HuntGroup;
18pub use crate::device::inbound_flow::InboundFlow;
19pub use crate::device::message_ani_router::MessageAniRouter;
20pub use crate::device::message_buttons::MessageButtons;
21pub use crate::device::message_dnis_router::MessageDnisRouter;
22pub use crate::device::message_plugin::MessagePlugin;
23pub use crate::device::message_template::MessageTemplate;
24pub use crate::device::message_text::MessageText;
25pub use crate::device::outbound_flow::OutboundFlow;
26pub use crate::device::play::Play;
27pub use crate::device::plugin::Plugin;
28pub use crate::device::queue::Queue;
29pub use crate::device::remote::Remote;
30pub use crate::device::say::Say;
31pub use crate::device::service::Service;
32pub use crate::device::shared::{RecordOptions, TranscribeOptions};
33pub use crate::device::sip_extension::SipExtension;
34pub use crate::device::sip_gateway::SipGateway;
35pub use crate::device::sms::Sms;
36pub use crate::device::tag_router::TagRouter;
37pub use crate::device::teams::Teams;
38pub use crate::device::time_range_router::TimeRangeRouter;
39pub use crate::device::voicemail::VoiceMail;
40pub use crate::device::whatsapp_flow::WhatsAppFlow;
41pub use crate::zone_router::ZoneRouter;
42use serde::{Deserialize, Deserializer, Serialize};
43use serde_json::Value;
44use crate::script::Script;
45use crate::tag::Tag;
46
47pub trait Connector {
48
49    fn get_connect_to(&mut self, state: &mut FlowState) -> ConnectState;
50
51    // Default implementation indicates this is not an endpoint
52    fn is_endpoint(&self) -> bool {
53        false
54    }
55
56    // Whether this device can route to other devices when in connector mode
57    fn supports_routing(&self) -> bool {
58        true
59    }
60}
61
62pub trait BaseDevice {
63    fn get_id(&mut self) -> String;
64    fn get_name(&mut self) -> String;
65    fn get_extension(&mut self) -> u16;
66}
67
68#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
69pub enum DeviceType {
70    #[serde(rename = "ROUTE_START")]
71    InboundFlow,
72    #[serde(rename = "MATCH_START")]
73    OutboundFlow,
74    #[serde(rename = "WHATSAPP_START")]
75    WhatsAppFlow,
76    #[serde(rename = "APP_START")]
77    AppFlow,
78    #[serde(rename = "ANI_ROUTER")]
79    AniRouter,
80    #[serde(rename = "DNIS_ROUTER")]
81    DnisRouter,
82    #[serde(rename = "ZONE_ROUTER")]
83    ZoneRouter,
84    #[serde(rename = "NUMBER_PLAN")]
85    DigitRouter,
86    #[serde(rename = "TIME_RANGE_ROUTER")]
87    TimeRangeRouter,
88    #[serde(rename = "DAY_OF_WEEK_ROUTER")]
89    DayOfWeekRouter,
90    #[serde(rename = "DATE_RANGE_ROUTER")]
91    DateRangeRouter,
92    #[serde(rename = "HUNT_GROUP")]
93    HuntGroup,
94    #[serde(rename = "CLIENT")]
95    Client,
96    #[serde(rename = "TEAMS")]
97    Teams,
98    #[serde(rename = "SIP")]
99    SipExtension,
100    #[serde(rename = "SIP_GATEWAY")]
101    SipGateway,
102    #[serde(rename = "REMOTE")]
103    Remote,
104    #[serde(rename = "PLUGIN")]
105    Plugin,
106    #[serde(rename = "PLAY")]
107    Play,
108    #[serde(rename = "SAY")]
109    Say,
110    #[serde(rename = "VOICEMAIL")]
111    Voicemail,
112    #[serde(rename = "SCRIPT")]
113    Script,
114    #[serde(rename = "QUEUE")]
115    Queue,
116    #[serde(rename = "SMS")]
117    Sms,
118    #[serde(rename = "EMAIL")]
119    Email,
120    #[serde(rename = "TAG")]
121    Tag,
122    #[serde(rename = "TAG_ROUTER")]
123    TagRouter,
124    #[serde(rename = "MESSAGE_PLUGIN")]
125    MessagePlugin,
126    #[serde(rename = "MESSAGE_TEXT")]
127    MessageText,
128    #[serde(rename = "MESSAGE_BUTTONS")]
129    MessageButtons,
130    #[serde(rename = "MESSAGE_TEMPLATE")]
131    MessageTemplate,
132    #[serde(rename = "MESSAGE_ANI_ROUTER")]
133    MessageAniRouter,
134    #[serde(rename = "SERVICE")]
135    Service,
136    //todo MESSAGE_BUTTONS, MESSAGE_TEMPLATE
137}
138
139#[derive(Serialize, Deserialize, Clone)]
140#[serde(untagged)]
141pub enum Device {
142    InboundFlow(InboundFlow),
143    OutboundFlow(OutboundFlow),
144    WhatsAppFlow(WhatsAppFlow),
145    AppFlow(AppFlow),
146    AniRouter(ANIRouter),
147    DnisRouter(DNISRouter),
148    DigitRouter(DigitRouter),
149    TimeRangeRouter(TimeRangeRouter),
150    DayOfWeekRouter(DayOfWeekRouter),
151    DateRangeRouter(DateRangeRouter),
152    ZoneRouter(ZoneRouter),
153    HuntGroup(HuntGroup),
154    Client(Client),
155    Teams(Teams),
156    SipExtension(SipExtension),
157    SipGateway(SipGateway),
158    Remote(Remote),
159    Plugin(Plugin),
160    Play(Play),
161    Say(Say),
162    Voicemail(VoiceMail),
163    Script(Script),
164    Queue(Queue),
165    Sms(Sms),
166    Email(Email),
167    Tag(Tag),
168    TagRouter(TagRouter),
169    MessagePlugin(MessagePlugin),
170    MessageButtons(MessageButtons),
171    MessageText(MessageText),
172    MessageTemplate(MessageTemplate),
173    MessageAniRouter(MessageAniRouter),
174    Service(Service),
175}
176
177#[derive(Serialize, Deserialize, Clone)]
178#[serde(rename_all = "camelCase")]
179pub struct DeviceStruct {
180    #[serde(rename = "_id")]
181    pub id: String,
182
183    #[serde(rename = "type")]
184    pub device_type: DeviceType,
185
186    pub name: String,
187
188    #[serde(deserialize_with = "from_str")]
189    pub extension: u16,
190
191    #[serde(default)]
192    pub tags: Vec<DeviceTag>,
193
194    #[serde(rename = "startRoute")]
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub start_route: Option<InboundFlow>,
197
198    #[serde(rename = "regexRoute")]
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub regex_route: Option<OutboundFlow>,
201
202    #[serde(rename = "appRoute")]
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub app_route: Option<AppFlow>,
205
206    #[serde(rename = "numberPlan")]
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub number_plan: Option<DigitRouter>,
209
210    #[serde(rename = "aniRouter")]
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub ani_router: Option<ANIRouter>,
213
214    #[serde(rename = "dnisRouter")]
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub dnis_router: Option<DNISRouter>,
217
218    #[serde(rename = "zoneRouter")]
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub zone_router: Option<ZoneRouter>,
221
222    #[serde(rename = "tagRouter")]
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub tag_router: Option<TagRouter>,
225
226    #[serde(rename = "timeRangeRoute")]
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub time_range_router: Option<TimeRangeRouter>,
229
230    #[serde(rename = "dayOfWeekRoute")]
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub day_of_week_router: Option<DayOfWeekRouter>,
233
234    #[serde(rename = "dateRangeRoute")]
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub date_range_router: Option<DateRangeRouter>,
237
238    #[serde(rename = "huntGroup")]
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub hunt_group: Option<HuntGroup>,
241
242    #[serde(rename = "client")]
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub client: Option<Client>,
245
246    #[serde(rename = "teams")]
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub teams: Option<Teams>,
249
250    #[serde(rename = "sipExtension")]
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub sip_extension: Option<SipExtension>,
253
254    #[serde(rename = "sipGateway")]
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub sip_gateway: Option<SipGateway>,
257
258    #[serde(rename = "remote")]
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub remote: Option<Remote>,
261
262    #[serde(rename = "voicemail")]
263    #[serde(skip_serializing_if = "Option::is_none")]
264    pub voice_mail: Option<VoiceMail>,
265
266    #[serde(rename = "queue")]
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub queue: Option<Queue>,
269
270    #[serde(rename = "plugin")]
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub plugin: Option<Plugin>,
273
274    #[serde(rename = "service")]
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub service: Option<Service>,
277
278    #[serde(rename = "play")]
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub play: Option<Play>,
281
282    #[serde(rename = "say")]
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub say: Option<Say>,
285
286    #[serde(rename = "script")]
287    #[serde(skip_serializing_if = "Option::is_none")]
288    pub script: Option<Script>,
289
290    #[serde(rename = "email")]
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub email: Option<Email>,
293
294    #[serde(rename = "sms")]
295    #[serde(skip_serializing_if = "Option::is_none")]
296    pub sms: Option<Sms>,
297
298    #[serde(rename = "tag")]
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub tag: Option<Tag>,
301
302    #[serde(rename = "event")]
303    #[serde(skip_serializing_if = "Option::is_none")]
304    pub event: Option<Event>,
305
306    #[serde(rename = "whatsAppRoute")]
307    #[serde(skip_serializing_if = "Option::is_none")]
308    pub whats_app_flow: Option<WhatsAppFlow>,
309
310    #[serde(rename = "messagePlugin")]
311    #[serde(skip_serializing_if = "Option::is_none")]
312    pub message_plugin: Option<MessagePlugin>,
313
314    #[serde(rename = "messageText")]
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub message_text: Option<MessageText>,
317
318    #[serde(rename = "messageButtons")]
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub message_buttons: Option<MessageButtons>,
321
322    #[serde(rename = "messageTemplate")]
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub message_template: Option<MessageTemplate>,
325
326    #[serde(rename = "messageANIRouter")]
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub message_ani_router: Option<MessageAniRouter>,
329
330    #[serde(rename = "messageDNISRouter")]
331    #[serde(skip_serializing_if = "Option::is_none")]
332    pub message_dnis_router: Option<MessageDnisRouter>,
333}
334
335fn from_str<'de, D>(deserializer: D) -> Result<u16, D::Error>
336where
337    D: Deserializer<'de>,
338{
339    let value = Value::deserialize(deserializer)?;
340    if value.is_string() {
341        Ok(value.as_str().unwrap().parse().unwrap())
342    } else if value.is_u64() {
343        Ok(value.as_u64().unwrap() as u16)
344    } else if value.is_i64() {
345        Ok(value.as_i64().unwrap() as u16)
346    } else {
347        Err(serde::de::Error::custom("Cannot map extension to u16"))
348    }
349}
350
351
352impl DeviceStruct {
353    pub fn record_options(&self) -> Option<RecordOptions> {
354        match &self.device_type {
355            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.record_options.clone()), // Cloning here
356            DeviceType::Client => self.client.as_ref().map(|c| c.record_options.clone()), // Cloning here
357            DeviceType::Teams => self.teams.as_ref().map(|t| t.record_options.clone()), // Cloning here
358            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.record_options.clone()), // Cloning here
359            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.record_options.clone()), // Cloning here
360            DeviceType::Remote => self.remote.as_ref().map(|r| r.record_options.clone()), // Cloning here
361            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.record_options.clone()), // Cloning here
362            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.record_options.clone()), // Cloning here
363            _ => None,
364        }
365    }
366
367    pub fn transcribe_options(&self) -> Option<TranscribeOptions> {
368        match &self.device_type {
369            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.transcribe_options.clone()),
370            DeviceType::Client => self.client.as_ref().map(|c| c.transcribe_options.clone()),
371            DeviceType::Teams => self.teams.as_ref().map(|t| t.transcribe_options.clone()),
372            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.transcribe_options.clone()),
373            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.transcribe_options.clone()),
374            DeviceType::Remote => self.remote.as_ref().map(|r| r.transcribe_options.clone()),
375            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.transcribe_options.clone()),
376            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.transcribe_options.clone()),
377            _ => None,
378        }
379    }
380
381    pub fn is_id(&self, _id: &str) -> bool {
382        self.id == _id
383    }
384
385    pub fn is_device_type(&self, device_type: DeviceType) -> bool {
386        self.device_type == device_type
387    }
388
389    pub fn match_device(&self, str: &str) -> bool {
390        let matched = match &self.device_type {
391            DeviceType::InboundFlow => {
392                self.start_route
393                    .as_ref()
394                    .map_or(false, |v| v.ddis.contains(&str.to_string()))
395            }
396            DeviceType::Client => {
397                self.client
398                    .as_ref()
399                    .map_or(false, |v| v.username.eq(str))
400            }
401            DeviceType::SipGateway => {
402                self.sip_gateway
403                    .as_ref()
404                    .map_or(false, |v| v.trunks.contains(&str.to_string()))
405            }
406            _ => false,
407        };
408
409        matched || self.id.eq(str) || self.extension.to_string().eq(str)
410    }
411
412    pub fn match_outbound_flow(&self) -> bool {
413        match &self.device_type {
414            DeviceType::OutboundFlow => true,
415            _ => false,
416        }
417    }
418
419    pub fn is_connector(&self) -> bool {
420        vec![
421            DeviceType::InboundFlow,
422            DeviceType::OutboundFlow,
423            DeviceType::AppFlow,
424            DeviceType::WhatsAppFlow,
425            DeviceType::AniRouter,
426            DeviceType::DnisRouter,
427            DeviceType::DigitRouter,
428            DeviceType::TimeRangeRouter,
429            DeviceType::DayOfWeekRouter,
430            DeviceType::DateRangeRouter,
431            DeviceType::Play,
432            DeviceType::Say,
433            DeviceType::Voicemail,
434            DeviceType::Script,
435            DeviceType::Queue,
436            DeviceType::Sms,
437            DeviceType::Email,
438            DeviceType::Tag,
439            DeviceType::TagRouter,
440            DeviceType::Service,
441        ]
442        .contains(&self.device_type)
443    }
444
445    pub fn is_call_handler(&self) -> bool {
446        vec![
447            DeviceType::HuntGroup,
448            DeviceType::Client,
449            DeviceType::Teams,
450            DeviceType::SipExtension,
451            DeviceType::SipGateway,
452            DeviceType::Remote,
453            DeviceType::Plugin,
454        ]
455        .contains(&self.device_type)
456    }
457}
458
459#[derive(Serialize, Deserialize, Clone)]
460#[serde(rename_all = "camelCase")]
461pub struct DeviceTag {
462    #[serde(rename = "type")]
463    pub tag_type: TagType,
464    pub name: String,
465    pub value: String,
466}
467
468#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
469#[serde(rename_all = "camelCase")]
470pub enum TagType {
471    Session,
472    Global,
473}
474
475
476pub trait Endpoint {
477    fn get_caller_id(&self, state: &FlowState) -> String {
478        state.initial_request.from.clone()
479    }
480    fn get_called_id(&self, state: &FlowState) -> String {
481        state.initial_request.to.clone()
482    }
483    fn get_listen(&self, state: &FlowState) -> Option<Listen>;
484    fn get_proxy(&self, _state: &FlowState, _regions:Vec<Arc<Region>>) -> Option<VoiceServer> {
485        None
486    }
487    fn get_transcribe(&self, _state: &FlowState) -> Option<TranscribeDial> {
488        None
489    }
490}
491
492
493
494
495// New trait for endpoint devices that can terminate calls
496pub trait EndpointDevice: Connector {
497    fn is_endpoint(&self) -> bool {
498        true
499    }
500
501    // This method returns the device type name for logging
502    fn device_type_name(&self) -> &'static str;
503
504    // Whether this endpoint can also act as a connector (for post-dial routing)
505    fn supports_routing(&self) -> bool {
506        false
507    }
508}
509
510
511
512//DEBUG
513
514// DeviceType Debug Implementation
515impl Debug for DeviceType {
516    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
517        match self {
518            DeviceType::InboundFlow => write!(f, "InboundFlow"),
519            DeviceType::OutboundFlow => write!(f, "OutboundFlow"),
520            DeviceType::WhatsAppFlow => write!(f, "WhatsAppFlow"),
521            DeviceType::AppFlow => write!(f, "AppFlow"),
522            DeviceType::AniRouter => write!(f, "AniRouter"),
523            DeviceType::DnisRouter => write!(f, "DnisRouter"),
524            DeviceType::DigitRouter => write!(f, "DigitRouter"),
525            DeviceType::TimeRangeRouter => write!(f, "TimeRangeRouter"),
526            DeviceType::DayOfWeekRouter => write!(f, "DayOfWeekRouter"),
527            DeviceType::DateRangeRouter => write!(f, "DateRangeRouter"),
528            DeviceType::ZoneRouter => write!(f, "ZoneRouter"),
529            DeviceType::HuntGroup => write!(f, "HuntGroup"),
530            DeviceType::Client => write!(f, "Client"),
531            DeviceType::Teams => write!(f, "Teams"),
532            DeviceType::SipExtension => write!(f, "SipExtension"),
533            DeviceType::SipGateway => write!(f, "SipGateway"),
534            DeviceType::Remote => write!(f, "Remote"),
535            DeviceType::Plugin => write!(f, "Plugin"),
536            DeviceType::Play => write!(f, "Play"),
537            DeviceType::Say => write!(f, "Say"),
538            DeviceType::Voicemail => write!(f, "Voicemail"),
539            DeviceType::Script => write!(f, "Script"),
540            DeviceType::Queue => write!(f, "Queue"),
541            DeviceType::Sms => write!(f, "Sms"),
542            DeviceType::Email => write!(f, "Email"),
543            DeviceType::Tag => write!(f, "Tag"),
544            DeviceType::TagRouter => write!(f, "TagRouter"),
545            DeviceType::MessagePlugin => write!(f, "MessagePlugin"),
546            DeviceType::MessageText => write!(f, "MessageText"),
547            DeviceType::MessageButtons => write!(f, "MessageButtons"),
548            DeviceType::MessageTemplate => write!(f, "MessageTemplate"),
549            DeviceType::MessageAniRouter => write!(f, "MessageAniRouter"),
550            DeviceType::Service => write!(f, "Service"),
551        }
552    }
553}
554
555
556
557// Device Enum Debug Implementation
558impl Debug for Device {
559    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
560        match self {
561            Device::InboundFlow(_) => write!(f, "Device::InboundFlow"),
562            Device::OutboundFlow(_) => write!(f, "Device::OutboundFlow"),
563            Device::WhatsAppFlow(_) => write!(f, "Device::WhatsAppFlow"),
564            Device::AppFlow(_) => write!(f, "Device::AppFlow"),
565            Device::AniRouter(_) => write!(f, "Device::AniRouter"),
566            Device::DnisRouter(_) => write!(f, "Device::DnisRouter"),
567            Device::DigitRouter(_) => write!(f, "Device::DigitRouter"),
568            Device::TimeRangeRouter(_) => write!(f, "Device::TimeRangeRouter"),
569            Device::DayOfWeekRouter(_) => write!(f, "Device::DayOfWeekRouter"),
570            Device::DateRangeRouter(_) => write!(f, "Device::DateRangeRouter"),
571            Device::ZoneRouter(_) => write!(f, "Device::ZoneRouter"),
572            Device::HuntGroup(_) => write!(f, "Device::HuntGroup"),
573            Device::Client(_) => write!(f, "Device::Client"),
574            Device::Teams(_) => write!(f, "Device::Teams"),
575            Device::SipExtension(_) => write!(f, "Device::SipExtension"),
576            Device::SipGateway(_) => write!(f, "Device::SipGateway"),
577            Device::Remote(_) => write!(f, "Device::Remote"),
578            Device::Plugin(_) => write!(f, "Device::Plugin"),
579            Device::Play(_) => write!(f, "Device::Play"),
580            Device::Say(_) => write!(f, "Device::Say"),
581            Device::Voicemail(_) => write!(f, "Device::Voicemail"),
582            Device::Script(_) => write!(f, "Device::Script"),
583            Device::Queue(_) => write!(f, "Device::Queue"),
584            Device::Sms(_) => write!(f, "Device::Sms"),
585            Device::Email(_) => write!(f, "Device::Email"),
586            Device::Tag(_) => write!(f, "Device::Tag"),
587            Device::TagRouter(_) => write!(f, "Device::TagRouter"),
588            Device::MessagePlugin(_) => write!(f, "Device::MessagePlugin"),
589            Device::MessageButtons(_) => write!(f, "Device::MessageButtons"),
590            Device::MessageText(_) => write!(f, "Device::MessageText"),
591            Device::MessageTemplate(_) => write!(f, "Device::MessageTemplate"),
592            Device::MessageAniRouter(_) => write!(f, "Device::MessageAniRouter"),
593            Device::Service(_) => write!(f, "Device::Service"),
594        }
595    }
596}
597
598// DeviceStruct Debug Implementation
599impl Debug for DeviceStruct {
600    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
601        f.debug_struct("DeviceStruct")
602            .field("id", &self.id)
603            .field("device_type", &self.device_type)
604            .field("name", &self.name)
605            .field("extension", &self.extension)
606            .finish_non_exhaustive()
607    }
608}
609
610// TagType Debug Implementation
611impl Debug for TagType {
612    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
613        match self {
614            TagType::Session => write!(f, "Session"),
615            TagType::Global => write!(f, "Global"),
616        }
617    }
618}
619
620// DeviceTag Debug Implementation
621impl Debug for DeviceTag {
622    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
623        f.debug_struct("DeviceTag")
624            .field("tag_type", &self.tag_type)
625            .field("name", &self.name)
626            .field("value", &self.value)
627            .finish()
628    }
629}
630
631
632
633
634
635// RecordOptions Debug Implementation
636impl Debug for RecordOptions {
637    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
638        f.debug_struct("RecordOptions")
639            .field("enabled", &self.enabled)
640            .field("retention", &self.retention)
641            .field("mix_type", &self.mix_type)
642            .field("sample_rate", &self.sample_rate)
643            .finish()
644    }
645}
646
647// TranscribeOptions Debug Implementation
648impl Debug for TranscribeOptions {
649    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
650        f.debug_struct("TranscribeOptions")
651            .field("enabled", &self.enabled)
652            .field("language", &self.language)
653            .finish()
654    }
655}
656
657// AsrVendor Debug Implementation
658impl Debug for AsrVendor {
659    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
660
661        match self {
662            AsrVendor::Google => write!(f, "Google"),
663            AsrVendor::Deepgram => write!(f, "DeepGram"),
664            AsrVendor::Microsoft => write!(f, "Microsoft"),
665            AsrVendor::Aws => write!(f, "Aws"),
666            AsrVendor::Ibm => write!(f, "Ibm"),
667            AsrVendor::Nuance => write!(f, "Nuance"),
668            AsrVendor::Nvidia =>write!(f, "Nvidia"),
669            AsrVendor::Soniox => write!(f, "Soniox"),
670        }
671    }
672}