3 #include "cmdhelp/libao-sound.hpp"
4 #include "core/audioapi-driver.hpp"
5 #include "core/command.hpp"
6 #include "core/dispatch.hpp"
7 #include "core/framerate.hpp"
8 #include "core/misc.hpp"
9 #include "core/framerate.hpp"
10 #include "core/keymapper.hpp"
11 #include "core/settings.hpp"
12 #include "core/messages.hpp"
13 #include "core/window.hpp"
14 #include "library/framebuffer.hpp"
15 #include "library/string.hpp"
25 #include "core/instance.hpp"
26 #include "library/minmax.hpp"
27 #include "library/workthread.hpp"
35 std::string current_device
= "";
36 ao_device
* volatile cdev
= NULL
;
37 bool init_flag
= false;
38 bool was_enabled
= false;
39 volatile bool do_quit_flag
= false;
40 volatile bool do_quit_ack
= false;
43 class cb_thread
: public workthread
46 cb_thread() { fire(); }
50 while(!do_quit_flag
) {
51 audioapi_get_mixed(buffer
, 512, true);
53 memset(buffer
, 0, sizeof(buffer
));
56 ao_play(d
, reinterpret_cast<char*>(buffer
), 2048);
64 cb_thread
* thread
= NULL
;
66 bool switch_devices(int newdevice
, std::string name
)
68 //If audio is open, close it.
72 //Wait a bit for the device to close.
76 audioapi_send_rate_change(0, 0);
81 strcpy(matrix
, "L,R");
82 ao_sample_format sformat
;
83 ao_option
* options
= NULL
;
87 sformat
.byte_format
= AO_FMT_NATIVE
;
88 sformat
.matrix
= matrix
;
89 std::string idno
= (stringfmt() << driver_id
).str();
90 ao_append_option(&options
, "id", idno
.c_str());
91 cdev
= ao_open_live(newdevice
, &sformat
, options
);
97 throw std::runtime_error("Bad driver ID");
99 throw std::runtime_error("Driver doesn't support playback");
101 throw std::runtime_error("Bad option value");
103 throw std::runtime_error("Can not open device");
105 throw std::runtime_error("Unknown error");
107 (stringfmt() << "Error code " << err
).throwex();
110 audioapi_send_rate_change(0, 48000);
113 current_device
= name
;
114 messages
<< "Switched to audio output " << name
<< std::endl
;
117 messages
<< "Switched to null audio output" << std::endl
;
122 command::fnptr
<const std::string
&> x(lsnes_cmds
, CLIBAOSND::setid
,
123 [](const std::string
& value
) throw(std::bad_alloc
, std::runtime_error
) {
124 driver_id
= parse_value
<int>(value
);
127 struct _audioapi_driver drv
= {
128 .init
= []() -> void {
134 int defaultid
= ao_default_driver_id();
135 std::string dname
= "";
136 ao_info
** drvs
= ao_driver_info_list(&dcount
);
137 messages
<< "Detected " << dcount
<< " sound output devices." << std::endl
;
138 for(int j
= 0; j
< dcount
; j
++) {
139 messages
<< "Audio device " << drvs
[j
]->short_name
<< ": " << drvs
[j
]->name
142 dname
= drvs
[j
]->short_name
;
144 thread
= new cb_thread
;
147 switch_devices(defaultid
, dname
);
149 switch_devices(-1, "");
152 .quit
= []() -> void {
155 switch_devices(-1, "");
160 do_quit_flag
= false;
162 //Threads are detecthed by default.
166 .enable
= [](bool enable
) -> void { was_enabled
= enable
; },
167 .initialized
= []() -> bool { return init_flag
; },
168 .set_device
= [](const std::string
& pdev
, const std::string
& rdev
) -> void {
170 //Sound input not supported.
171 throw std::runtime_error("Invalid sound input device");
173 if(!switch_devices(-1, ""))
174 throw std::runtime_error("Failed to switch sound outputs");
176 int idx
= ao_driver_id(pdev
.c_str());
178 throw std::runtime_error("Invalid output device '" + pdev
+ "'");
180 if(!switch_devices(idx
, pdev
))
181 throw std::runtime_error("Failed to switch sound outputs");
182 } catch(std::exception
& e
) {
183 throw std::runtime_error(std::string("Failed to switch sound outputs: ") +
188 .get_device
= [](bool rec
) -> std::string
{
190 return "null"; //Sound input not supported.
191 if(current_device
== "")
194 return current_device
;
196 .get_devices
= [](bool rec
) -> std::map
<std::string
, std::string
> {
197 std::map
<std::string
, std::string
> ret
;
199 ret
["null"] = "null sound input";
202 ret
["null"] = "null sound output";
204 ao_info
** drvs
= ao_driver_info_list(&dcount
);
207 for(int j
= 0; j
< dcount
; j
++)
208 if(drvs
[j
]->type
== AO_TYPE_LIVE
)
209 ret
[drvs
[j
]->short_name
] = drvs
[j
]->name
;
212 .name
= []() -> const char* { return "Libao sound plugin"; }
214 audioapi_driver
_drv(drv
);