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