1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
use chrono::Duration;
use serde::de::DeserializeOwned;

use super::Client;
use crate::common::MonitorType;
use crate::requests::{
    AddFilter, MoveFilter, ReorderFilter, RequestType, SourceFilterSettings,
    SourceFilterVisibility, SourceScreenshot, SourceSettings, TextFreetype2Properties,
    TextGdiPlusProperties, Volume,
};
use crate::responses;
use crate::Result;

/// API functions related to sources.
pub struct Sources<'a> {
    pub(super) client: &'a Client,
}

impl<'a> Sources<'a> {
    /// List all sources available in the running OBS instance.
    pub async fn get_sources_list(&self) -> Result<Vec<responses::SourceListItem>> {
        self.client
            .send_message::<responses::SourcesList>(RequestType::GetSourcesList)
            .await
            .map(|sl| sl.sources)
    }

    /// Get a list of all available sources types.
    pub async fn get_sources_types_list(&self) -> Result<Vec<responses::SourceTypeItem>> {
        self.client
            .send_message::<responses::SourceTypesList>(RequestType::GetSourceTypesList)
            .await
            .map(|stl| stl.types)
    }

    /// Get the volume of the specified source. Default response uses mul format, NOT SLIDER
    /// PERCENTAGE.
    ///
    /// - `source`: Source name.
    /// - `use_decibel`: Output volume in decibels of attenuation instead of amplitude/mul.
    pub async fn get_volume(
        &self,
        source: &str,
        use_decibel: Option<bool>,
    ) -> Result<responses::Volume> {
        self.client
            .send_message(RequestType::GetVolume {
                source,
                use_decibel,
            })
            .await
    }

    /// Set the volume of the specified source. Default request format uses mul, NOT SLIDER
    /// PERCENTAGE.
    pub async fn set_volume(&self, volume: Volume<'_>) -> Result<()> {
        self.client
            .send_message(RequestType::SetVolume(volume))
            .await
    }

    /// Get the mute status of a specified source.
    ///
    /// - `source`: Source name.
    pub async fn get_mute(&self, source: &str) -> Result<responses::Mute> {
        self.client
            .send_message(RequestType::GetMute { source })
            .await
    }

    /// Sets the mute status of a specified source.
    ///
    /// - `source`: Source name.
    /// - `mute`: Desired mute status.
    pub async fn set_mute(&self, source: &str, mute: bool) -> Result<()> {
        self.client
            .send_message(RequestType::SetMute { source, mute })
            .await
    }

    /// Inverts the mute status of a specified source.
    ///
    /// - `source`: Source name.
    pub async fn toggle_mute(&self, source: &str) -> Result<()> {
        self.client
            .send_message(RequestType::ToggleMute { source })
            .await
    }

    /// Note: If the new name already exists as a source, obs-websocket will return an error.
    ///
    /// - `source_name`: Source name.
    /// - `new_name`: New source name.
    pub async fn set_source_name(&self, source_name: &str, new_name: &str) -> Result<()> {
        self.client
            .send_message(RequestType::SetSourceName {
                source_name,
                new_name,
            })
            .await
    }

    /// Set the audio sync offset of a specified source.
    ///
    /// - `source`: Source name.
    /// - `offset`: The desired audio sync offset (in nanoseconds).
    pub async fn set_sync_offset(&self, source: &str, offset: Duration) -> Result<()> {
        self.client
            .send_message(RequestType::SetSyncOffset { source, offset })
            .await
    }

    /// Get the audio sync offset of a specified source.
    ///
    /// - `source`: Source name.
    pub async fn get_sync_offset(&self, source: &str) -> Result<responses::SyncOffset> {
        self.client
            .send_message(RequestType::GetSyncOffset { source })
            .await
    }

    /// Get settings of the specified source.
    ///
    /// - `source_name`: Source name.
    /// - `source_type`: Type of the specified source. Useful for type-checking if you expect a
    ///   specific settings schema.
    pub async fn get_source_settings<T>(
        &self,
        source_name: &str,
        source_type: Option<&str>,
    ) -> Result<responses::SourceSettings<T>>
    where
        T: DeserializeOwned,
    {
        self.client
            .send_message(RequestType::GetSourceSettings {
                source_name,
                source_type,
            })
            .await
    }

    /// Set settings of the specified source.
    pub async fn set_source_settings<T>(
        &self,
        source_settings: SourceSettings<'_>,
    ) -> Result<responses::SourceSettings<T>>
    where
        T: DeserializeOwned,
    {
        self.client
            .send_message(RequestType::SetSourceSettings(source_settings))
            .await
    }

    /// Get the current properties of a Text GDI Plus source.
    ///
    /// - `source`: Source name.
    pub async fn get_text_gdi_plus_properties(
        &self,
        source: &str,
    ) -> Result<responses::TextGdiPlusProperties> {
        self.client
            .send_message(RequestType::GetTextGDIPlusProperties { source })
            .await
    }

    /// Set the current properties of a Text GDI Plus source.
    pub async fn set_text_gdi_plus_properties(
        &self,
        properties: TextGdiPlusProperties<'_>,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::SetTextGDIPlusProperties(Box::new(properties)))
            .await
    }

    /// Get the current properties of a Text Freetype 2 source.
    ///
    /// - `source`: Source name.
    pub async fn get_text_freetype2_properties(
        &self,
        source: &str,
    ) -> Result<responses::TextFreetype2Properties> {
        self.client
            .send_message(RequestType::GetTextFreetype2Properties { source })
            .await
    }

    /// Set the current properties of a Text Freetype 2 source.
    pub async fn set_text_freetype2_properties(
        &self,
        properties: TextFreetype2Properties<'_>,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::SetTextFreetype2Properties(properties))
            .await
    }

    /// Get configured special sources like Desktop Audio and Mic/Aux sources.
    pub async fn get_special_sources(&self) -> Result<responses::SpecialSources> {
        self.client
            .send_message(RequestType::GetSpecialSources)
            .await
    }

    /// List filters applied to a source
    ///
    /// - `source_name`: Source name.
    pub async fn get_source_filters(
        &self,
        source_name: &str,
    ) -> Result<Vec<responses::SourceFilter>> {
        self.client
            .send_message::<responses::SourceFilters>(RequestType::GetSourceFilters { source_name })
            .await
            .map(|sf| sf.filters)
    }

    /// List filters applied to a source.
    ///
    /// - `source_name`: Source name.
    /// - `filter_name`: Source filter name.
    pub async fn get_source_filter_info<T>(
        &self,
        source_name: &str,
        filter_name: &str,
    ) -> Result<responses::SourceFilterInfo<T>>
    where
        T: DeserializeOwned,
    {
        self.client
            .send_message(RequestType::GetSourceFilterInfo {
                source_name,
                filter_name,
            })
            .await
    }

    /// Add a new filter to a source. Available source types along with their settings properties
    /// are available from [`get_sources_types_list`](Self::get_sources_types_list).
    pub async fn add_filter_to_source(&self, add_filter: AddFilter<'_>) -> Result<()> {
        self.client
            .send_message(RequestType::AddFilterToSource(add_filter))
            .await
    }

    /// Remove a filter from a source.
    ///
    /// - `source_name`: Name of the source from which the specified filter is removed.
    /// - `filter_name`: Name of the filter to remove.
    pub async fn remove_filter_from_source(
        &self,
        source_name: &str,
        filter_name: &str,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::RemoveFilterFromSource {
                source_name,
                filter_name,
            })
            .await
    }

    /// Move a filter in the chain (absolute index positioning).
    pub async fn reorder_source_filter(&self, reorder_filter: ReorderFilter<'_>) -> Result<()> {
        self.client
            .send_message(RequestType::ReorderSourceFilter(reorder_filter))
            .await
    }

    /// Move a filter in the chain (relative positioning).
    pub async fn move_source_filter(&self, move_filter: MoveFilter<'_>) -> Result<()> {
        self.client
            .send_message(RequestType::MoveSourceFilter(move_filter))
            .await
    }

    /// Update settings of a filter.
    pub async fn set_source_filter_settings(
        &self,
        settings: SourceFilterSettings<'_>,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::SetSourceFilterSettings(settings))
            .await
    }

    /// Change the visibility/enabled state of a filter.
    pub async fn set_source_filter_visibility(
        &self,
        visibility: SourceFilterVisibility<'_>,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::SetSourceFilterVisibility(visibility))
            .await
    }

    /// Get the audio monitoring type of the specified source.
    ///
    /// - `source_name`: Source name.
    pub async fn get_audio_monitor_type(&self, source_name: &str) -> Result<MonitorType> {
        self.client
            .send_message::<responses::AudioMonitorType>(RequestType::GetAudioMonitorType {
                source_name,
            })
            .await
            .map(|amt| amt.monitor_type)
    }

    /// Set the audio monitoring type of the specified source.
    ///
    /// - `source_name`: Source name.
    /// - `monitor_type`: The monitor type to use. Options: `none`, `monitorOnly`,
    ///   `monitorAndOutput`.
    pub async fn set_audio_monitor_type(
        &self,
        source_name: &str,
        monitor_type: MonitorType,
    ) -> Result<()> {
        self.client
            .send_message(RequestType::SetAudioMonitorType {
                source_name,
                monitor_type,
            })
            .await
    }

    /// At least [`embed_picture_format`](SourceScreenshot::embed_picture_format) or
    /// [`save_to_file_path`](SourceScreenshot::save_to_file_path) must be specified.
    ///
    /// Clients can specify [`width`](SourceScreenshot::width) and
    /// [`height`](SourceScreenshot::height) parameters to receive scaled pictures. Aspect ratio is
    /// preserved if only one of these two parameters is specified.
    pub async fn take_source_screenshot(
        &self,
        source_screenshot: SourceScreenshot<'_>,
    ) -> Result<responses::SourceScreenshot> {
        self.client
            .send_message(RequestType::TakeSourceScreenshot(source_screenshot))
            .await
    }
}