source: mainline/uspace/app/dplay/dplay.c@ 4bec78f

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

dplay: Update to use new interface.

Ugly and broken, but compiles fine.

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2011 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 dplay
30 * @{
31 */
32/**
33 * @file PCM playback audio devices
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <str_error.h>
39#include <str.h>
40#include <devman.h>
41#include <audio_pcm_buffer_iface.h>
42#include <stdio.h>
43#include <sys/mman.h>
44#include <sys/time.h>
45
46#include <stdio.h>
47#include <macros.h>
48
49#include "wave.h"
50
51#define DEFAULT_DEVICE "/hw/pci0/00:01.0/sb16/dsp"
52#define SUBBUFFERS 4
53
54typedef struct {
55 struct {
56 void *base;
57 size_t size;
58 unsigned id;
59 void* position;
60 } buffer;
61 FILE* source;
62} playback_t;
63
64
65static void device_event_callback(ipc_callid_t id, ipc_call_t *call, void* arg)
66{
67 if (IPC_GET_IMETHOD(*call) != IPC_FIRST_USER_METHOD) {
68 printf("Unknown event.\n");
69 return;
70 }
71 playback_t *pb = arg;
72 printf("Got device event!!!\n");
73 const size_t buffer_part = pb->buffer.size / SUBBUFFERS;
74 const size_t bytes = fread(pb->buffer.position, sizeof(uint8_t),
75 buffer_part, pb->source);
76 if (bytes == 0)
77 exit(0); // ugly but temporary
78 pb->buffer.position += bytes;
79 if (bytes != buffer_part)
80 bzero(pb->buffer.position, buffer_part - bytes);
81 pb->buffer.position += buffer_part - bytes;
82 if (pb->buffer.position >= (pb->buffer.base + pb->buffer.size))
83 pb->buffer.position = pb->buffer.base;
84}
85
86
87static void play(async_exch_t *device, playback_t *pb,
88 unsigned sampling_rate, unsigned sample_size, unsigned channels, bool sign)
89{
90 assert(device);
91 assert(pb);
92 pb->buffer.position = pb->buffer.base;
93 printf("Playing: %dHz, %d-bit samples, %d channel(s), %sSIGNED.\n",
94 sampling_rate, sample_size, channels, sign ? "": "UN");
95 const size_t bytes = fread(pb->buffer.base, sizeof(uint8_t),
96 pb->buffer.size, pb->source);
97 if (bytes != pb->buffer.size)
98 return;
99 printf("Buffer data ready.\n");
100 sleep(10);
101#if 0
102 const size_t update_size = size / SUBBUFFERS;
103
104 /* Time to play half the buffer. */
105 const suseconds_t interval = 1000000 /
106 (sampling_rate / (update_size / (channels * (sample_size / 8))));
107 printf("Time to play half buffer: %ld us.\n", interval);
108 /* Initialize buffer. */
109 const size_t bytes = fread(buffer, sizeof(uint8_t), size, source);
110 if (bytes != size)
111 return;
112
113 struct timeval time;
114 gettimeofday(&time, NULL);
115 printf("Starting playback.\n");
116 int ret = audio_pcm_buffer_start_playback(device, buffer_id, SUBBUFFERS,
117 sampling_rate, sample_size, channels, sign);
118 if (ret != EOK) {
119 printf("Failed to start playback: %s.\n", str_error(ret));
120 return;
121 }
122 void *buffer_place = buffer;
123 while (true) {
124 tv_add(&time, interval); /* Next update point */
125
126 struct timeval current;
127 gettimeofday(&current, NULL);
128
129 const suseconds_t delay = min(tv_sub(&time, &current), interval);
130 if (delay > 0)
131 udelay(delay);
132
133 const size_t bytes =
134 fread(buffer_place, sizeof(uint8_t), update_size, source);
135 if (bytes == 0)
136 break;
137 if (bytes < update_size) {
138 bzero(buffer_place + bytes, update_size - bytes);
139 }
140 buffer_place += update_size;
141
142 if (buffer_place == buffer + size) {
143 buffer_place = buffer;
144 }
145 }
146
147 printf("Stopping playback.\n");
148 ret = audio_pcm_buffer_stop_playback(device, buffer_id);
149 if (ret != EOK) {
150 printf("Failed to stop playback: %s.\n", str_error(ret));
151 }
152#endif
153}
154
155int main(int argc, char *argv[])
156{
157 const char *device = DEFAULT_DEVICE;
158 const char *file;
159 switch (argc) {
160 case 2:
161 file = argv[1];
162 break;
163 case 3:
164 device = argv[1];
165 file = argv[2];
166 break;
167 default:
168 printf("Usage: %s [device] file.\n", argv[0]);
169 return 1;
170 }
171
172 devman_handle_t pcm_handle;
173 int ret = devman_fun_get_handle(device, &pcm_handle, 0);
174 if (ret != EOK) {
175 printf("Failed to get device(%s) handle: %s.\n",
176 device, str_error(ret));
177 return 1;
178 }
179
180 async_sess_t *session = devman_device_connect(
181 EXCHANGE_SERIALIZE, pcm_handle, IPC_FLAG_BLOCKING);
182 if (!session) {
183 printf("Failed to connect to device.\n");
184 return 1;
185 }
186
187 async_exch_t *exch = async_exchange_begin(session);
188 if (!exch) {
189 printf("Failed to start session exchange.\n");
190 async_hangup(session);
191 return 1;
192 }
193 const char* info = NULL;
194 ret = audio_pcm_buffer_get_info_str(exch, &info);
195 if (ret != EOK) {
196 printf("Failed to get PCM info.\n");
197 async_exchange_end(exch);
198 async_hangup(session);
199 return 1;
200 }
201 printf("Playing on %s.\n", info);
202 free(info);
203
204 playback_t pb = {{0}, NULL};
205 pb.buffer.size = 4096;
206 printf("Requesting buffer: %p, %zu, %u.\n", pb.buffer.base, pb.buffer.size, pb.buffer.id);
207 ret = audio_pcm_buffer_get_buffer(exch, &pb.buffer.base,
208 &pb.buffer.size, &pb.buffer.id, device_event_callback, &pb);
209 if (ret != EOK) {
210 printf("Failed to get PCM buffer: %s.\n", str_error(ret));
211 async_exchange_end(exch);
212 async_hangup(session);
213 return 1;
214 }
215 printf("Buffer (%u): %p %zu.\n", pb.buffer.id, pb.buffer.base,
216 pb.buffer.size);
217
218 pb.source = fopen(file, "rb");
219 if (pb.source == NULL) {
220 printf("Failed to open %s.\n", file);
221 munmap(pb.buffer.base, pb.buffer.size);
222 audio_pcm_buffer_release_buffer(exch, pb.buffer.id);
223 async_exchange_end(exch);
224 async_hangup(session);
225 return 1;
226 }
227 wave_header_t header;
228 fread(&header, sizeof(header), 1, pb.source);
229 unsigned rate, sample_size, channels;
230 bool sign;
231 const char *error;
232 ret = wav_parse_header(&header, NULL, NULL, &rate, &sample_size,
233 &channels, &sign, &error);
234 if (ret != EOK) {
235 printf("Error parsing wav header: %s.\n", error);
236 fclose(pb.source);
237 munmap(pb.buffer.base, pb.buffer.size);
238 audio_pcm_buffer_release_buffer(exch, pb.buffer.id);
239 async_exchange_end(exch);
240 async_hangup(session);
241 return 1;
242 }
243
244 play(exch, &pb, rate, sample_size, channels, sign);
245
246 munmap(pb.buffer.base, pb.buffer.size);
247 audio_pcm_buffer_release_buffer(exch, pb.buffer.id);
248 async_exchange_end(exch);
249 async_hangup(session);
250 return 0;
251}
252/**
253 * @}
254 */
Note: See TracBrowser for help on using the repository browser.