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/audioapi.hpp"
26 #include "core/instance.hpp"
27 #include "library/minmax.hpp"
28 #include "library/workthread.hpp"
33 #include <boost/lexical_cast.hpp>
37 std::string current_device
= "";
38 ao_device
* volatile cdev
= NULL
;
39 bool init_flag
= false;
40 bool was_enabled
= false;
43 class cb_thread
: public workthread
46 cb_thread() { fire(); }
51 lsnes_instance
.audio
->get_mixed(buffer
, 512, true);
53 memset(buffer
, 0, sizeof(buffer
));
56 ao_play(d
, reinterpret_cast<char*>(buffer
), 2048);
63 bool switch_devices(int newdevice
, std::string name
)
65 //If audio is open, close it.
69 //Wait a bit for the device to close.
73 lsnes_instance
.audio
->voice_rate(0, 0);
78 strcpy(matrix
, "L,R");
79 ao_sample_format sformat
;
80 ao_option
* options
= NULL
;
84 sformat
.byte_format
= AO_FMT_NATIVE
;
85 sformat
.matrix
= matrix
;
86 std::string idno
= (stringfmt() << driver_id
).str();
87 ao_append_option(&options
, "id", idno
.c_str());
88 cdev
= ao_open_live(newdevice
, &sformat
, options
);
94 throw std::runtime_error("Bad driver ID");
96 throw std::runtime_error("Driver doesn't support playback");
98 throw std::runtime_error("Bad option value");
100 throw std::runtime_error("Can not open device");
102 throw std::runtime_error("Unknown error");
104 (stringfmt() << "Error code " << err
).throwex();
107 lsnes_instance
.audio
->voice_rate(0, 48000);
110 current_device
= name
;
111 messages
<< "Switched to audio output " << name
<< std::endl
;
114 messages
<< "Switched to null audio output" << std::endl
;
119 command::fnptr
<const std::string
&> x(lsnes_cmds
, CLIBAOSND::setid
,
120 [](const std::string
& value
) throw(std::bad_alloc
, std::runtime_error
) {
121 driver_id
= parse_value
<int>(value
);
124 struct _audioapi_driver drv
= {
125 .init
= []() -> void {
131 int defaultid
= ao_default_driver_id();
132 std::string dname
= "";
133 ao_info
** drvs
= ao_driver_info_list(&dcount
);
134 messages
<< "Detected " << dcount
<< " sound output devices." << std::endl
;
135 for(int j
= 0; j
< dcount
; j
++) {
136 messages
<< "Audio device " << drvs
[j
]->short_name
<< ": " << drvs
[j
]->name
139 dname
= drvs
[j
]->short_name
;
144 switch_devices(defaultid
, dname
);
146 switch_devices(-1, "");
149 .quit
= []() -> void {
152 switch_devices(-1, "");
156 .enable
= [](bool enable
) -> void { was_enabled
= enable
; },
157 .initialized
= []() -> bool { return init_flag
; },
158 .set_device
= [](const std::string
& pdev
, const std::string
& rdev
) -> void {
160 //Sound input not supported.
161 throw std::runtime_error("Invalid sound input device");
163 if(!switch_devices(-1, ""))
164 throw std::runtime_error("Failed to switch sound outputs");
166 int idx
= ao_driver_id(pdev
.c_str());
168 throw std::runtime_error("Invalid output device '" + pdev
+ "'");
170 if(!switch_devices(idx
, pdev
))
171 throw std::runtime_error("Failed to switch sound outputs");
172 } catch(std::exception
& e
) {
173 throw std::runtime_error(std::string("Failed to switch sound outputs: ") +
178 .get_device
= [](bool rec
) -> std::string
{
180 return "null"; //Sound input not supported.
181 if(current_device
== "")
184 return current_device
;
186 .get_devices
= [](bool rec
) -> std::map
<std::string
, std::string
> {
187 std::map
<std::string
, std::string
> ret
;
189 ret
["null"] = "null sound input";
192 ret
["null"] = "null sound output";
194 ao_info
** drvs
= ao_driver_info_list(&dcount
);
197 for(int j
= 0; j
< dcount
; j
++)
198 if(drvs
[j
]->type
== AO_TYPE_LIVE
)
199 ret
[drvs
[j
]->short_name
] = drvs
[j
]->name
;
202 .name
= []() -> const char* { return "Libao sound plugin"; }
204 audioapi_driver
_drv(drv
);