10#define DDEBUG(...) Ase::debug ("driver", __VA_ARGS__)
15Driver::Driver (
const String &driver,
const String &devid) :
16 driver_ (driver), devid_ (devid)
26 return devid_.
empty() ? driver_ : driver_ +
"=" + devid_;
31Driver::priority_string (
uint priority)
34 if (priority & SURROUND) b.
push_back (
"SURROUND");
35 if (priority & HEADSET) b.
push_back (
"HEADSET");
36 if (priority & RECORDER) b.
push_back (
"RECORDER");
37 if (priority & MIDI_THRU) b.
push_back (
"MIDI_THRU");
38 if (priority & JACK) b.
push_back (
"JACK");
39 if (priority & ALSA_USB) b.
push_back (
"ALSA_USB");
40 if (priority & ALSA_KERN) b.
push_back (
"ALSA_KERN");
42 if (priority & PULSE) b.
push_back (
"PULSE");
43 if (priority & ALSA_USER) b.
push_back (
"ALSA_USER");
44 if (priority & PSEUDO) b.
push_back (
"PSEUDO");
45 if (priority & PAUTO) b.
push_back (
"PAUTO");
46 if (priority & PNULL) b.
push_back (
"PNULL");
47 if (priority & WCARD) b.
push_back (
"WCARD");
48 if (priority & WDEV) b.
push_back (
"WDEV");
49 if (priority & WSUB) b.
push_back (
"WSUB");
54using RegisteredLoaderFunc =
Error (*) ();
56 const char *
const what;
57 const RegisteredLoaderFunc func;
61static bool registered_loaders_executed =
false;
68 assert_return (registered_loaders_executed ==
false,
nullptr);
70 lv.push_back ({ staticwhat, loader });
71 return ®istered_loaders_executed;
79 registered_loaders_executed =
true;
80 for (
auto &loader : registered_loaders())
82 Error error = loader.func ();
83 if (error != Error::NONE)
84 printerr (
"ASE: %s: loading failed: %s\n", loader.what,
ase_error_blurb (error));
89template<
typename DriverP>
97 registered_driver_vector()
100 return registered_driver_vector_;
108 const String driverid = kvpair_key (devid);
109 for (
const auto &driver : registered_driver_vector())
110 if (driver.driver_id_ == driverid)
112 create = driver.create_;
115 Error error = Error::DEVICE_NOT_AVAILABLE;
116 DriverP driver = create ? create (devid) : NULL;
119 error = opener (driver, iodir);
122 if (error == Error::NONE)
125 assert_return (!(iodir & Driver::READONLY) || driver->readable(),
nullptr);
126 assert_return (!(iodir & Driver::WRITEONLY) || driver->writable(),
nullptr);
137 register_driver (
const String &driverid,
141 auto &vec = registered_driver_vector();
146 static Driver::EntryVec
147 list_drivers (
const Driver::EntryVec &pseudos)
149 Driver::EntryVec entries;
151 auto &vec = registered_driver_vector();
152 for (
const auto &rd : vec)
154 Driver::EntryVec dentries;
156 for (
auto &entry : dentries)
157 entry.devid = entry.devid.empty() ? rd.driver_id_ : rd.driver_id_ +
"=" + entry.devid;
161 return a.priority < b.priority;
168PcmDriver::PcmDriver (
const String &driver,
const String &devid) :
176 auto opener = [&config] (
PcmDriverP d, IODir iodir) {
177 return d->open (iodir, config);
181 for (
const auto &entry : list_drivers())
182 if (entry.priority < PSEUDO &&
183 !(entry.priority & 0x0000ffff))
187 if (!pcm_driver && required && desired != required) {
198 if (!pcm_driver && required && desired != required)
207PcmDriver::register_driver (
const String &driverid,
215PcmDriver::list_drivers ()
218 entry.devid =
"auto";
219 entry.device_name =
_(
"Automatic driver selection");
220 entry.device_info =
_(
"Selects the first available PCM card or sound server");
221 entry.readonly =
false;
222 entry.writeonly =
false;
223 entry.priority = Driver::PAUTO;
224 Driver::EntryVec pseudos;
225 pseudos.push_back (entry);
226 return RegisteredDriver<PcmDriverP>::list_drivers (pseudos);
230MidiDriver::MidiDriver (
const String &driver,
const String &devid) :
231 Driver (driver, devid)
235MidiDriver::open (
const String &devid, IODir iodir,
Error *ep)
237 auto opener = [] (MidiDriverP d, IODir iodir) {
238 return d->open (iodir);
242 for (
const auto &entry : list_drivers())
243 if (entry.priority < PSEUDO)
245 MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (entry.devid, iodir, ep, opener);
253 MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (
devid, iodir, ep, opener);
261MidiDriver::register_driver (
const String &driverid,
265 return RegisteredDriver<MidiDriverP>::register_driver (driverid, create, list);
269MidiDriver::list_drivers ()
272 entry.devid =
"auto";
273 entry.device_name =
_(
"Automatic MIDI driver selection");
274 entry.device_info =
_(
"Selects the first available MIDI device");
275 entry.readonly =
false;
276 entry.writeonly =
false;
277 entry.priority = Driver::PAUTO;
278 Driver::EntryVec pseudos;
279 pseudos.push_back (entry);
280 return RegisteredDriver<MidiDriverP>::list_drivers (pseudos);
285 uint n_channels_ = 0;
287 uint block_size_ = 0;
288 int64 resumetime_ = 0;
298 pcm_n_channels ()
const override
303 pcm_mix_freq ()
const override
308 pcm_block_length ()
const override
313 pcm_latency (
uint *rlatency,
uint *wlatency)
const override
315 *rlatency = mix_freq_ / 10;
316 *wlatency = mix_freq_ / 10;
322 flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
329 const bool require_readable = iodir == READONLY || iodir == READWRITE;
330 const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
331 flags_ |= Flags::READABLE * require_readable;
332 flags_ |= Flags::WRITABLE * require_writable;
333 n_channels_ = config.n_channels;
334 mix_freq_ = config.mix_freq;
335 block_size_ = config.block_length;
336 flags_ |= Flags::OPENED;
337 DDEBUG (
"NULL-PCM: opening with freq=%f channels=%d: %s", mix_freq_, n_channels_,
ase_error_blurb (Error::NONE));
341 pcm_check_io (
int64 *timeout_usecs)
override
344 if (resumetime_ > current_usecs)
346 *timeout_usecs = resumetime_ - current_usecs;
349 resumetime_ = current_usecs;
353 pcm_write (
size_t n,
const float *values)
override
355 const int64 busy_usecs = n * 1000000 / (mix_freq_ * n_channels_);
356 resumetime_ += busy_usecs;
359 pcm_read (
size_t n,
float *values)
override
365 list_drivers (Driver::EntryVec &entries)
369 entry.device_name =
"Null PCM Driver";
370 entry.device_info =
_(
"Discard all PCM output and provide zeros as PCM input");
371 entry.notice =
"Warning: The Null driver has no playback timing support";
372 entry.readonly =
false;
373 entry.writeonly =
false;
374 entry.priority = Driver::PNULL;
375 entries.push_back (entry);
379static const String null_pcm_driverid = PcmDriver::register_driver (
"null", NullPcmDriver::create, NullPcmDriver::list_drivers);
395 flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
398 open (IODir iodir)
override
402 const bool require_readable = iodir == READONLY || iodir == READWRITE;
403 const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
404 flags_ |= Flags::READABLE * require_readable;
405 flags_ |= Flags::WRITABLE * require_writable;
406 flags_ |= Flags::OPENED;
411 has_events ()
override
421 list_drivers (Driver::EntryVec &entries)
425 entry.device_name =
"Null MIDI Driver";
426 entry.device_info =
_(
"Discard all MIDI events");
427 entry.readonly =
false;
428 entry.writeonly =
false;
429 entry.priority = Driver::PNULL;
430 entries.push_back (entry);
434static const String null_midi_driverid = MidiDriver::register_driver (
"null", NullMidiDriver::create, NullMidiDriver::list_drivers);
442try_load_libasejack ()
445 const std::string libasejack = string_format (
"%s/lib/jackdriver.so", anklang_runpath (RPath::INSTALLDIR));
446 if (Path::check (libasejack,
"fr"))
448 void *dlhandle =
dlopen (libasejack.
c_str(), RTLD_LOCAL | RTLD_NOW);
450 DDEBUG (
"%s: dlopen: %s", libasejack, dlhandle ?
"OK" : err ? err :
"unknown dlerror");
T back_inserter(T... args)
Base class for a PCM and MIDI devices.
String devid() const
Return a string which uniquely identifies this driver and device.
Base class for a MIDI devices.
A stream of writable MidiEvent structures.
Base class for a PCM devices.
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define _(...)
Retrieve the translation of a C or C++ string.
T make_move_iterator(T... args)
The Anklang C++ API namespace.
void floatfill(float *dst, float f, size_t n)
Fill n values of dst with f.
String string_join(const String &junctor, const StringS &strvec)
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
Error
Enum representing Error states.
const char * ase_error_blurb(Error error)
Describe Error condition.
bool * register_driver_loader(const char *staticwhat, Error(*loader)())
Register loader callbacks at static constructor time.
std::string String
Convenience alias for std::string.
uint32_t uint
Provide 'uint' as convenience type.
void load_registered_drivers()
Load all registered drivers.
uint64 timestamp_realtime()
Return the current time as uint64 in µseconds.
Driver information for PCM and MIDI handling.
PCM device configuration.