1 /// 2 /// LibAO output. 3 /// Audio output support for playing via libao. 4 /// @file libaooutput.cpp - pianod2 5 /// @author Perette Barella 6 /// @date 2015-11-18 7 /// @copyright Copyright (c) 2015-2016 Devious Fish. All rights reserved. 8 /// 9 10 #include <config.h> 11 12 #include <stdexcept> 13 14 #include <errno.h> 15 16 #include <ao/ao.h> 17 18 #include "logging.h" 19 #include "audiooutput.h" 20 #include "libaooutput.h" 21 22 using namespace std; 23 24 namespace Audio { 25 /// Mutex to restrict concurrent calls into libao API. 26 std::mutex LibaoOutput::ao_mutex; 27 28 /** Open audio output using libAO. 29 @param settings Device/ driver/ host to use for output. 30 @param data_format The format in which samples will arrive for output. */ 31 LibaoOutput::LibaoOutput (const AudioSettings &settings, 32 const AudioFormat &data_format) { 33 34 ao_sample_format format = {}; 35 format.bits = data_format.bits; 36 format.rate = data_format.rate; 37 format.channels = data_format.channels; 38 format.byte_format = (data_format.arrangement == SampleArrangement::Big ? AO_FMT_BIG : 39 data_format.arrangement == SampleArrangement::Little ? AO_FMT_LITTLE : 40 AO_FMT_NATIVE); 41 42 // Find driver, or use default if unspecified. 43 int audio_out_driver = (settings.output_driver.empty() 44 ? ao_default_driver_id() 45 : ao_driver_id (settings.output_driver.c_str())); 46 if (audio_out_driver < 0) { 47 flog (LOG_WHERE (LOG_ERROR), "Audio driver ", 48 settings.output_driver.empty() ? "(default)" : settings.output_driver.c_str(), 49 " not found"); 50 throw invalid_argument ("Invalid audio driver"); 51 } 52 53 // Create a list of ao_options 54 ao_option *options = nullptr; 55 ao_append_option(&options, "client_name", PACKAGE); 56 if (settings.output_device != "") { 57 ao_append_option (&options, "dev", settings.output_device.c_str()); 58 } 59 if (settings.output_id != "") { 60 ao_append_option (&options, "id", settings.output_id.c_str()); 61 } 62 if (settings.output_server != "") { 63 ao_append_option (&options, "server", settings.output_server.c_str()); 64 } 65 { 66 lock_guard<mutex> lock (ao_mutex); 67 device = ao_open_live (audio_out_driver, 68 & const_cast <ao_sample_format &> (format), 69 options); 70 } 71 ao_free_options (options); 72 if (device == NULL) { 73 const char *reason = (errno == AO_ENODRIVER ? "No driver" : 74 errno == AO_ENOTLIVE ? "Not a live output device" : 75 errno == AO_EBADOPTION ? "Bad option" : 76 errno == AO_EOPENDEVICE ? "Cannot open device" : "Other failure"); 77 flog (LOG_WHERE (LOG_ERROR), "Cannot open audio device ", 78 settings.output_device.empty() ? "default" : settings.output_device.c_str(), 79 "/", 80 settings.output_id.empty() ? "default" : settings.output_id.c_str(), 81 "/", 82 settings.output_server.empty() ? "default" : settings.output_server.c_str(), 83 ": ", reason); 84 throw AudioException (string (__func__) + ": " + reason); 85 } 86 87 bytes_per_sample_set = data_format.sampleGroupSize(); 88 } 89 90 /** Play output. 91 @param buffer The samples, in packed (interleaved) format if multichannel. 92 @param number_of_bytes Size of the buffer; number of samples is determined 93 by the audio format set when opening the channel. */ 94 bool LibaoOutput::play (void *buffer, unsigned number_of_bytes) { 95 lock_guard<mutex> lock (ao_mutex); 96 return ao_play(device, (char *) buffer, number_of_bytes); 97 }; 98 99 LibaoOutput::~LibaoOutput () { 100 lock_guard<mutex> lock (ao_mutex); 101 ao_close (device); 102 }; 103 104 } 105