source: mainline/uspace/app/wavplay/main.c@ 9e1800c

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

libhound: Implement hound client side API sing client side protocol headers

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