source: mainline/uspace/app/dplay/dplay.c@ c891eaca

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

dplay: Use octo buffering instead of double buffering.

Improves sound quality on qemu.

  • Property mode set to 100644
File size: 5.6 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
53static void play(async_exch_t *device, unsigned buffer_id,
54 void *buffer, size_t size, FILE *source,
55 unsigned sampling_rate, unsigned sample_size, unsigned channels, bool sign)
56{
57 assert(device);
58 const size_t update_size = size / 8;
59
60 /* Time to play half the buffer. */
61 const suseconds_t interval = 1000000 /
62 (sampling_rate / (update_size / (channels * (sample_size / 8))));
63 printf("Time to play half buffer: %ld us.\n", interval);
64 /* Initialize buffer. */
65 const size_t bytes = fread(buffer, sizeof(uint8_t), size, source);
66 if (bytes != size)
67 return;
68
69 struct timeval time;
70 gettimeofday(&time, NULL);
71 printf("Starting playback.\n");
72 int ret = audio_pcm_buffer_start_playback(device, buffer_id,
73 sampling_rate, sample_size, channels, sign);
74 if (ret != EOK) {
75 printf("Failed to start playback: %s.\n", str_error(ret));
76 return;
77 }
78 void *buffer_place = buffer;
79 while (true) {
80 tv_add(&time, interval); /* Next update point */
81
82 struct timeval current;
83 gettimeofday(&current, NULL);
84
85 const suseconds_t delay = min(tv_sub(&time, &current), interval);
86 if (delay > 0)
87 usleep(delay);
88
89 const size_t bytes =
90 fread(buffer_place, sizeof(uint8_t), update_size, source);
91 if (bytes == 0)
92 break;
93 if (bytes < update_size) {
94 bzero(buffer_place + bytes, update_size - bytes);
95 }
96 buffer_place += update_size;
97
98 if (buffer_place == buffer + size) {
99 buffer_place = buffer;
100 }
101 }
102
103 printf("Stopping playback.\n");
104 ret = audio_pcm_buffer_stop_playback(device, buffer_id);
105 if (ret != EOK) {
106 printf("Failed to stop playback: %s.\n", str_error(ret));
107 }
108}
109
110int main(int argc, char *argv[])
111{
112 const char *device = DEFAULT_DEVICE;
113 const char *file;
114 switch (argc) {
115 case 2:
116 file = argv[1];
117 break;
118 case 3:
119 device = argv[1];
120 file = argv[2];
121 break;
122 default:
123 printf("Usage: %s [device] file.\n", argv[0]);
124 return 1;
125 }
126
127 devman_handle_t pcm_handle;
128 int ret = devman_fun_get_handle(device, &pcm_handle, 0);
129 if (ret != EOK) {
130 printf("Failed to get device(%s) handle: %s.\n",
131 device, str_error(ret));
132 return 1;
133 }
134
135 async_sess_t *session = devman_device_connect(
136 EXCHANGE_ATOMIC, pcm_handle, IPC_FLAG_BLOCKING);
137 if (!session) {
138 printf("Failed to connect to device.\n");
139 return 1;
140 }
141
142 async_exch_t *exch = async_exchange_begin(session);
143 if (!exch) {
144 printf("Failed to start session exchange.\n");
145 async_hangup(session);
146 return 1;
147 }
148 const char* info;
149 ret = audio_pcm_buffer_get_info_str(exch, &info);
150 if (ret != EOK) {
151 printf("Failed to get PCM info.\n");
152 async_exchange_end(exch);
153 async_hangup(session);
154 return 1;
155 }
156 printf("Playing on %s.\n", info);
157 free(info);
158
159 void *buffer = NULL;
160 size_t size = 0;
161 unsigned id = 0;
162 ret = audio_pcm_buffer_get_buffer(exch, &buffer, &size, &id);
163 if (ret != EOK) {
164 printf("Failed to get PCM buffer: %s.\n", str_error(ret));
165 async_exchange_end(exch);
166 async_hangup(session);
167 return 1;
168 }
169 printf("Buffer (%u): %p %zu.\n", id, buffer, size);
170
171 FILE *source = fopen(file, "rb");
172 if (source == NULL) {
173 printf("Failed to open %s.\n", file);
174 munmap(buffer, size);
175 audio_pcm_buffer_release_buffer(exch, id);
176 async_exchange_end(exch);
177 async_hangup(session);
178 return 1;
179 }
180 wave_header_t header;
181 fread(&header, sizeof(header), 1, source);
182 unsigned rate, sample_size, channels;
183 bool sign;
184 const char *error;
185 ret = wav_parse_header(&header, NULL, NULL, &rate, &sample_size,
186 &channels, &sign, &error);
187 if (ret != EOK) {
188 printf("Error parsing wav header: %s.\n", error);
189 fclose(source);
190 munmap(buffer, size);
191 audio_pcm_buffer_release_buffer(exch, id);
192 async_exchange_end(exch);
193 async_hangup(session);
194 return 1;
195 }
196
197 play(exch, id, buffer, size, source, rate, sample_size, channels, sign);
198
199 munmap(buffer, size);
200 audio_pcm_buffer_release_buffer(exch, id);
201 async_exchange_end(exch);
202 async_hangup(session);
203 return 0;
204}
205/**
206 * @}
207 */
Note: See TracBrowser for help on using the repository browser.