@@ -176,3 +176,51 @@ bool devices_match(const char *id1, const char *id2)
176176
177177 return match ;
178178}
179+
180+ static inline bool device_is_input (const char * device )
181+ {
182+ return astrstri (device , "soundflower" ) == NULL && astrstri (device , "wavtap" ) == NULL &&
183+ astrstri (device , "soundsiphon" ) == NULL && astrstri (device , "ishowu" ) == NULL &&
184+ astrstri (device , "blackhole" ) == NULL && astrstri (device , "loopback" ) == NULL &&
185+ astrstri (device , "groundcontrol" ) == NULL && astrstri (device , "vbcable" ) == NULL ;
186+ }
187+
188+ static bool find_loopback_cb (void * param , const char * name , const char * id )
189+ {
190+ UNUSED_PARAMETER (name );
191+ char * * p_id = param ;
192+
193+ if (!device_is_input (id )) {
194+ * p_id = bstrdup (id );
195+ return false;
196+ }
197+ return true;
198+ }
199+
200+ void get_desktop_default_id (char * * p_id )
201+ {
202+ if (* p_id )
203+ return ;
204+
205+ AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultSystemOutputDevice ,
206+ kAudioObjectPropertyScopeGlobal , kAudioObjectPropertyElementMain };
207+
208+ AudioDeviceID id = 0 ;
209+ UInt32 size = sizeof (id );
210+ OSStatus stat = AudioObjectGetPropertyData (kAudioObjectSystemObject , & addr , 0 , NULL , & size , & id );
211+
212+ if (success (stat , "AudioObjectGetPropertyData" )) {
213+ /* Try system default output first */
214+ obs_enum_audio_monitoring_device (alloc_default_id , p_id , id , false);
215+
216+ /* If not a loopback, try to find a virtual (non-input) device instead */
217+ if (* p_id && device_is_input (* p_id )) {
218+ bfree (* p_id );
219+ * p_id = NULL ;
220+ enum_audio_devices (find_loopback_cb , p_id , false);
221+ }
222+ }
223+
224+ if (!* p_id )
225+ * p_id = bzalloc (1 );
226+ }
0 commit comments