source: mainline/uspace/app/wavplay/main.c@ bd5860f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bd5860f was bd5860f, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

wavplay: Add more debug output and few fixes

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
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 wavplay
30 * @{
31 */
32/**
33 * @file PCM playback audio devices
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <fibril_synch.h>
39#include <str_error.h>
40#include <stdio.h>
41#include <hound/client.h>
42#include <pcm/sample_format.h>
43#include <getopt.h>
44
45#include "dplay.h"
46#include "wave.h"
47
48#define BUFFER_SIZE (4 * 1024)
49
50
51static int hplay(const char *filename)
52{
53 printf("HPLAY: %s\n", filename);
54 FILE *source = fopen(filename, "rb");
55 if (!source) {
56 printf("Failed to open file %s\n", filename);
57 return EINVAL;
58 }
59 wave_header_t header;
60 size_t read = fread(&header, sizeof(header), 1, source);
61 if (read != 1) {
62 printf("Failed to read WAV header: %zu\n", read);
63 fclose(source);
64 return EIO;
65 }
66 pcm_format_t format;
67 const char *error;
68 int ret = wav_parse_header(&header, NULL, NULL, &format.channels,
69 &format.sampling_rate, &format.sample_format, &error);
70 if (ret != EOK) {
71 printf("Error parsing wav header: %s.\n", error);
72 fclose(source);
73 return EINVAL;
74 }
75 hound_context_t *hound = hound_context_create_playback(filename,
76 format, 0);
77 if (!hound) {
78 printf("Failed to create HOUND context\n");
79 fclose(source);
80 return ENOMEM;
81 }
82
83 ret = hound_context_connect_target(hound, "default");
84 if (ret != EOK) {
85 printf("Failed to connect to default target: %s\n",
86 str_error(ret));
87 fclose(source);
88 return ENOMEM;
89 }
90 static char buffer[BUFFER_SIZE];
91 while ((read = fread(buffer, sizeof(char), BUFFER_SIZE, source)) > 0) {
92 ret = hound_write_main_stream(hound, buffer, read);
93 if (ret != EOK) {
94 printf("Failed to write to main context stream: %s\n",
95 str_error(ret));
96 break;
97 }
98 }
99 fclose(source);
100 return ret;
101}
102
103typedef struct {
104 FILE *source;
105 volatile bool playing;
106 fibril_mutex_t mutex;
107 fibril_condvar_t cv;
108 hound_sess_t *server;
109} playback_t;
110
111static void playback_initialize(playback_t *pb, hound_sess_t *sess)
112{
113 assert(pb);
114 pb->playing = false;
115 pb->source = NULL;
116 pb->server = sess;
117 fibril_mutex_initialize(&pb->mutex);
118 fibril_condvar_initialize(&pb->cv);
119}
120
121static void data_callback(void* arg, void *buffer, ssize_t size)
122{
123 playback_t *pb = arg;
124 assert(pb);
125
126 if (size > 0) {
127 const ssize_t bytes =
128 fread(buffer, sizeof(uint8_t), size, pb->source);
129 printf("%zu bytes ready\n", bytes);
130 if (bytes < size) {
131 printf(" requested: %zd ready: %zd zero: %zd\n",
132 size, bytes, size - bytes);
133 bzero(buffer + bytes, size - bytes);
134 }
135 if (bytes == 0) {
136 pb->playing = false;
137 printf("The end, nothing more to play.\n");
138 fibril_condvar_signal(&pb->cv);
139 }
140 } else {
141 printf("Got error %s.\n", str_error(size));
142 pb->playing = false;
143 fibril_condvar_signal(&pb->cv);
144 }
145}
146
147static int play_hound(const char *filename)
148{
149 hound_sess_t *sess = hound_get_session();
150 if (!sess) {
151 printf("Failed to connect to hound service\n");
152 return 1;
153 }
154 playback_t pb;
155 playback_initialize(&pb, sess);
156 pb.source = fopen(filename, "rb");
157 if (pb.source == NULL) {
158 printf("Failed to open %s.\n", filename);
159 hound_release_session(sess);
160 return 1;
161 }
162 wave_header_t header;
163 fread(&header, sizeof(header), 1, pb.source);
164 unsigned rate, channels;
165 pcm_sample_format_t format;
166 const char *error;
167 int ret = wav_parse_header(&header, NULL, NULL, &channels, &rate,
168 &format, &error);
169 if (ret != EOK) {
170 printf("Error parsing wav header: %s.\n", error);
171 fclose(pb.source);
172 hound_release_session(sess);
173 return 1;
174 }
175
176 /* Create playback client */
177 ret = hound_register_playback(pb.server, filename, channels, rate,
178 format, data_callback, &pb);
179 if (ret != EOK) {
180 printf("Failed to register playback: %s\n", str_error(ret));
181 fclose(pb.source);
182 hound_release_session(sess);
183 return 1;
184 }
185
186 /* Connect */
187 ret = hound_create_connection(pb.server, filename, DEFAULT_SINK);
188 if (ret == EOK) {
189 fibril_mutex_lock(&pb.mutex);
190 for (pb.playing = true; pb.playing;
191 fibril_condvar_wait(&pb.cv, &pb.mutex));
192 fibril_mutex_unlock(&pb.mutex);
193
194 hound_destroy_connection(pb.server, filename, DEFAULT_SINK);
195 } else
196 printf("Failed to connect: %s\n", str_error(ret));
197
198 printf("Unregistering playback\n");
199 hound_unregister_playback(pb.server, filename);
200 printf("Releasing session\n");
201 hound_release_session(sess);
202 fclose(pb.source);
203 return 0;
204}
205
206static const struct option opts[] = {
207 {"device", required_argument, 0, 'd'},
208 {"record", no_argument, 0, 'r'},
209 {"help", no_argument, 0, 'h'},
210 {0, 0, 0, 0}
211};
212
213static void print_help(const char* name)
214{
215 printf("Usage: %s [options] file\n", name);
216 printf("supported options:\n");
217 printf("\t -h, --help\t Print this help.\n");
218 printf("\t -r, --record\t Start recording instead of playback.\n");
219 printf("\t -d, --device\t Use specified device instead of sound "
220 "service. Use location path or special device `default'\n");
221}
222
223int main(int argc, char *argv[])
224{
225 const char *device = "default";
226 int idx = 0;
227 bool direct = false, record = false;
228 optind = 0;
229 int ret = 0;
230 while (ret != -1) {
231 ret = getopt_long(argc, argv, "d:rh", opts, &idx);
232 switch (ret) {
233 case 'd':
234 direct = true;
235 device = optarg;
236 break;
237 case 'r':
238 record = true;
239 break;
240 case 'h':
241 print_help(*argv);
242 return 0;
243 };
244 }
245
246 if (optind == argc) {
247 printf("Not enough arguments.\n");
248 print_help(*argv);
249 return 1;
250 }
251 const char *file = argv[optind];
252
253 printf("%s %s\n", record ? "Recording" : "Playing", file);
254 if (record) {
255 printf("Recording is not supported yet.\n");
256 return 1;
257 }
258 if (direct)
259 return dplay(device, file);
260 else
261 return play_hound(file);
262 hplay(file);
263}
264/**
265 * @}
266 */
Note: See TracBrowser for help on using the repository browser.