source: mainline/uspace/app/modplay/modplay.c

Last change on this file was 87822ce, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Avoid infinite loop when console communication is broken

Need to make sure callers of console_get_event_timeout() can distinguish
between timeout and I/O error. Fix all callers of console_get_event()
and console_get_event_timeout() not to enter infinite loop when console
connection is broken. Also avoid setting of errno variable.

  • Property mode set to 100644
File size: 4.6 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup modplay
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <errno.h>
37#include <hound/client.h>
38#include <io/console.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <str.h>
42#include <str_error.h>
43#include <trackmod.h>
44
45static bool quit = false;
46
47static void modplay_key_press(kbd_event_t *ev)
48{
49 if ((ev->mods & KM_ALT) == 0 &&
50 (ev->mods & KM_SHIFT) == 0 &&
51 (ev->mods & KM_CTRL) != 0) {
52 if (ev->key == KC_Q)
53 quit = true;
54 }
55}
56
57static void modplay_event(cons_event_t *event)
58{
59 switch (event->type) {
60 case CEV_KEY:
61 if (event->ev.key.type == KEY_PRESS) {
62 modplay_key_press(&event->ev.key);
63 }
64 break;
65 default:
66 break;
67 }
68}
69
70static void print_syntax(void)
71{
72 printf("syntax: modplay [<options>] <filename.mod>\n");
73 printf("options:\n");
74 printf("\t-t <target>\tOutput to specified audio target.\n");
75}
76
77int main(int argc, char *argv[])
78{
79 trackmod_module_t *mod;
80 trackmod_modplay_t *modplay;
81 hound_context_t *hound;
82 console_ctrl_t *con;
83 cons_event_t event;
84 usec_t timeout;
85 pcm_format_t format;
86 void *buffer;
87 size_t buffer_size;
88 const char *target = HOUND_DEFAULT_TARGET;
89 errno_t rc;
90
91 ++argv;
92 --argc;
93
94 while (argc > 0 && (*argv)[0] == '-') {
95 if (str_cmp(*argv, "-t") == 0) {
96 ++argv;
97 --argc;
98
99 if (argc < 1) {
100 printf("Option '-t' requires an argument.\n");
101 print_syntax();
102 return 1;
103 }
104
105 target = *argv++;
106 --argc;
107 continue;
108 }
109
110 printf("Invalid option '%s'\n", *argv);
111 print_syntax();
112 return 1;
113 }
114
115 if (argc != 1) {
116 print_syntax();
117 return 1;
118 }
119
120 con = console_init(stdin, stdout);
121
122 rc = trackmod_module_load(argv[0], &mod);
123 if (rc != EOK) {
124 printf("Error loading %s.\n", argv[0]);
125 return 1;
126 }
127
128 format.channels = 1;
129 format.sampling_rate = 44100;
130#ifdef __LE__
131 format.sample_format = PCM_SAMPLE_SINT16_LE;
132#else
133 format.sample_format = PCM_SAMPLE_SINT16_BE;
134#endif
135 buffer_size = 64 * 1024;
136
137 buffer = malloc(buffer_size);
138 if (buffer == NULL) {
139 printf("Error allocating audio buffer.\n");
140 return 1;
141 }
142
143 hound = hound_context_create_playback(argv[1], format, buffer_size);
144 if (hound == NULL) {
145 printf("Error creating playback context.\n");
146 return 1;
147 }
148
149 rc = hound_context_connect_target(hound, target);
150 if (rc != EOK) {
151 printf("Error connecting audio target '%s': %s.\n",
152 target, str_error(rc));
153
154 char **names = NULL;
155 size_t count = 0;
156 rc = hound_context_get_available_targets(hound, &names, &count);
157 if (rc == EOK) {
158 printf("Available targets:\n");
159 for (size_t i = 0; i < count; i++)
160 printf(" - %s\n", names[i]);
161 }
162
163 return 1;
164 }
165
166 rc = trackmod_modplay_create(mod, format.sampling_rate, &modplay);
167 if (rc != EOK) {
168 printf("Error setting up playback.\n");
169 return 1;
170 }
171
172 printf("Playing '%s'. Press Ctrl+Q to quit.\n", argv[1]);
173
174 while (true) {
175 timeout = 0;
176 rc = console_get_event_timeout(con, &event, &timeout);
177 if (rc == EOK)
178 modplay_event(&event);
179 else if (rc != ETIMEOUT)
180 break;
181
182 if (quit)
183 break;
184
185 trackmod_modplay_get_samples(modplay, buffer, buffer_size / 4);
186
187 rc = hound_write_main_stream(hound, buffer, buffer_size / 4);
188 if (rc != EOK) {
189 printf("Error writing audio stream.\n");
190 break;
191 }
192 }
193
194 hound_context_destroy(hound);
195 trackmod_modplay_destroy(modplay);
196 trackmod_module_destroy(mod);
197
198 return 0;
199}
200
201/** @}
202 */
Note: See TracBrowser for help on using the repository browser.