1 /// 2 /// Parser for audio options. 3 /// Parse audio options for creating or reconfiguring a room. 4 /// @file audiooptionsparser.cpp - pianod2 5 /// @author Perette Barella 6 /// @date 2015-11-23 7 /// @copyright Copyright (c) 2015-2017 Devious Fish. All rights reserved. 8 /// 9 10 #include <config.h> 11 12 #include "audiooptionsparser.h" 13 #include "audiooutput.h" 14 15 namespace AudioOptions { 16 /** Validate audio settings. 17 @param settings The audio settings to validate. 18 @throw An appropriate command error if the settings are invalid. */ validate(const AudioSettings settings)19 void validate (const AudioSettings settings) { 20 if (settings.preroll_time == 0.0f && settings.crossfade_time > 0.0f) { 21 throw CommandError (E_INVALID, "Cannot crossfade without preroll."); 22 } 23 try { 24 if (!Audio::Output::isValidOutput (settings)) { 25 throw CommandError (E_NOTFOUND, settings.output_library); 26 } 27 } catch (const Audio::AudioException &e) { 28 throw CommandError (E_INVALID, e.what()); 29 } 30 if (settings.preroll_time > 0.0f) { 31 try { 32 if (!Audio::Output::outputCanCrossfade (settings)) { 33 throw CommandError (E_INVALID, "Cannot crossfade."); 34 } 35 } catch (const Audio::AudioException &e) { 36 throw CommandError (E_INVALID, e.what()); 37 } 38 } 39 } 40 41 42 static const Parser::ParseDefinition audioOptionStatements [] = { 43 { Option::Library, "library {library} ..." }, // Choose output library 44 { Option::Driver, "driver {driver} ..." }, // output setting 45 { Option::Device, "device {device} ..." }, // output setting 46 { Option::Id, "id {#id} ..." }, // output setting 47 { Option::Options, "options {options} ..." }, // output setting 48 { Option::Server, "server {server} ..." }, // output setting 49 { Option::Volume, "volume {#level:-100-100 ..."}, // room volume 50 { Option::CrossfadeTime, "crossfade duration {#seconds:0.0-15} ..." }, // How much volume adjustment when crossfading 51 { Option::CrossfadeLevel, "crossfade level {#level:0.0-50} ..." }, // How long to overlap songs 52 { Option::PrerollTime, "preroll duration {#seconds:0.0-30} ..." }, // Advance cueing time to allow buffering 53 { (Option) CMD_INVALID, NULL } 54 }; 55 56 /** AudioOptions is the parser that fills in the AudioSettings structure. */ handleOption(Option option,AudioSettings & dest)57 int Parser::handleOption (Option option, AudioSettings &dest) { 58 switch (option) { 59 case Option::Driver: 60 dest.output_driver = argv ("driver"); 61 return FB_PARSE_SUCCESS; 62 case Option::Device: 63 dest.output_device = argv ("device"); 64 return FB_PARSE_SUCCESS; 65 case Option::Id: 66 dest.output_id = argv ("id"); 67 return FB_PARSE_SUCCESS; 68 case Option::Options: 69 dest.output_options = argv ("options"); 70 return FB_PARSE_SUCCESS; 71 case Option::Server: 72 dest.output_server = argv ("server"); 73 return FB_PARSE_SUCCESS; 74 case Option::Library: 75 dest.output_library = argv ("library"); 76 return FB_PARSE_SUCCESS; 77 case Option::Volume: 78 dest.volume = strtod (argv ("level"), nullptr); 79 return FB_PARSE_SUCCESS; 80 case Option::CrossfadeTime: 81 dest.crossfade_time = strtod (argv ("seconds"), nullptr); 82 return FB_PARSE_SUCCESS; 83 case Option::CrossfadeLevel: 84 dest.crossfade_level = strtod (argv ("level"), nullptr); 85 return FB_PARSE_SUCCESS; 86 case Option::PrerollTime: 87 dest.preroll_time = strtod (argv ("seconds"), nullptr); 88 return FB_PARSE_SUCCESS; 89 } 90 assert (0); 91 return FB_PARSE_FAILURE; 92 } 93 Parser()94 Parser::Parser () { 95 addStatements (audioOptionStatements); 96 }; 97 interpret(const std::vector<std::string> & options,AudioSettings & result,PianodConnection & conn)98 int Parser::interpret(const std::vector<std::string> &options, AudioSettings &result, PianodConnection &conn) { 99 if (options.size()) { 100 int status = Football::OptionParser<AudioSettings, Option>::interpret (options, result, &conn); 101 if (status != FB_PARSE_SUCCESS) 102 return status; 103 validate (result); 104 } 105 return FB_PARSE_SUCCESS; 106 }; 107 108 Parser parser; 109 110 } 111