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

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

Drop id parameter from audio_pcm interface.

Independent buffer should have separate nodes.

  • Property mode set to 100644
File size: 6.5 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 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_iface.h>
42#include <fibril_synch.h>
43#include <stdio.h>
44#include <sys/mman.h>
45#include <sys/time.h>
46
47#include <stdio.h>
48#include <macros.h>
49
50#include "wave.h"
51
52#define DEFAULT_DEVICE "/hw/pci0/00:01.0/sb16/pcm"
53#define SUBBUFFERS 2
54
55typedef struct {
56 struct {
57 void *base;
58 size_t size;
59 void* position;
60 } buffer;
61 FILE* source;
62 volatile bool playing;
63 fibril_mutex_t mutex;
64 fibril_condvar_t cv;
65 async_exch_t *device;
66} playback_t;
67
68static void playback_initialize(playback_t *pb, async_exch_t *exch)
69{
70 assert(exch);
71 assert(pb);
72 pb->buffer.base = NULL;
73 pb->buffer.size = 0;
74 pb->buffer.position = NULL;
75 pb->playing = false;
76 pb->source = NULL;
77 pb->device = exch;
78 fibril_mutex_initialize(&pb->mutex);
79 fibril_condvar_initialize(&pb->cv);
80}
81
82
83static void device_event_callback(ipc_callid_t iid, ipc_call_t *icall, void* arg)
84{
85 async_answer_0(iid, EOK);
86 playback_t *pb = arg;
87 const size_t buffer_part = pb->buffer.size / SUBBUFFERS;
88 while (1) {
89 ipc_call_t call;
90 ipc_callid_t callid = async_get_call(&call);
91 switch(IPC_GET_IMETHOD(call)) {
92 case PCM_EVENT_PLAYBACK_DONE:
93 printf("+");
94 async_answer_0(callid, EOK);
95 break;
96 case PCM_EVENT_PLAYBACK_TERMINATED:
97 printf("\nPlayback terminated\n");
98 fibril_mutex_lock(&pb->mutex);
99 pb->playing = false;
100 fibril_condvar_signal(&pb->cv);
101 async_answer_0(callid, EOK);
102 fibril_mutex_unlock(&pb->mutex);
103 return;
104 default:
105 printf("Unknown event %d.\n", IPC_GET_IMETHOD(call));
106 async_answer_0(callid, ENOTSUP);
107 continue;
108
109 }
110 const size_t bytes = fread(pb->buffer.position, sizeof(uint8_t),
111 buffer_part, pb->source);
112 if (bytes == 0) {
113 audio_pcm_stop_playback(pb->device);
114 }
115 bzero(pb->buffer.position + bytes, buffer_part - bytes);
116 pb->buffer.position += buffer_part;
117
118 if (pb->buffer.position >= (pb->buffer.base + pb->buffer.size))
119 pb->buffer.position = pb->buffer.base;
120 }
121}
122
123
124static void play(playback_t *pb, unsigned channels, unsigned sampling_rate,
125 pcm_sample_format_t format)
126{
127 assert(pb);
128 assert(pb->device);
129 pb->buffer.position = pb->buffer.base;
130 printf("Playing: %dHz, %s, %d channel(s).\n",
131 sampling_rate, pcm_sample_format_str(format), channels);
132 const size_t bytes = fread(pb->buffer.base, sizeof(uint8_t),
133 pb->buffer.size, pb->source);
134 if (bytes != pb->buffer.size)
135 bzero(pb->buffer.base + bytes, pb->buffer.size - bytes);
136 printf("Buffer data ready.\n");
137 fibril_mutex_lock(&pb->mutex);
138 int ret = audio_pcm_start_playback(pb->device,
139 SUBBUFFERS, channels, sampling_rate, format);
140 if (ret != EOK) {
141 fibril_mutex_unlock(&pb->mutex);
142 printf("Failed to start playback: %s.\n", str_error(ret));
143 return;
144 }
145
146 for (pb->playing = true; pb->playing;
147 fibril_condvar_wait(&pb->cv, &pb->mutex));
148
149 fibril_mutex_unlock(&pb->mutex);
150 printf("\n");
151}
152
153int main(int argc, char *argv[])
154{
155 const char *device = DEFAULT_DEVICE;
156 const char *file;
157 switch (argc) {
158 case 2:
159 file = argv[1];
160 break;
161 case 3:
162 device = argv[1];
163 file = argv[2];
164 break;
165 default:
166 printf("Usage: %s [device] file.\n", argv[0]);
167 return 1;
168 }
169
170 devman_handle_t pcm_handle;
171 int ret = devman_fun_get_handle(device, &pcm_handle, 0);
172 if (ret != EOK) {
173 printf("Failed to get device(%s) handle: %s.\n",
174 device, str_error(ret));
175 return 1;
176 }
177
178 async_sess_t *session = devman_device_connect(
179 EXCHANGE_SERIALIZE, pcm_handle, IPC_FLAG_BLOCKING);
180 if (!session) {
181 printf("Failed to connect to device.\n");
182 return 1;
183 }
184
185 async_exch_t *exch = async_exchange_begin(session);
186 if (!exch) {
187 ret = EPARTY;
188 printf("Failed to start session exchange.\n");
189 goto close_session;
190 }
191 const char* info = NULL;
192 ret = audio_pcm_get_info_str(exch, &info);
193 if (ret != EOK) {
194 printf("Failed to get PCM info.\n");
195 goto close_session;
196 }
197 printf("Playing on %s.\n", info);
198 free(info);
199
200 playback_t pb;
201 playback_initialize(&pb, exch);
202
203 ret = audio_pcm_get_buffer(pb.device, &pb.buffer.base,
204 &pb.buffer.size, device_event_callback, &pb);
205 if (ret != EOK) {
206 printf("Failed to get PCM buffer: %s.\n", str_error(ret));
207 goto close_session;
208 }
209 printf("Buffer: %p %zu.\n", pb.buffer.base, pb.buffer.size);
210 uintptr_t ptr = 0;
211 as_get_physical_mapping(pb.buffer.base, &ptr);
212 printf("buffer mapped at %x.\n", ptr);
213
214 pb.source = fopen(file, "rb");
215 if (pb.source == NULL) {
216 ret = ENOENT;
217 printf("Failed to open %s.\n", file);
218 goto cleanup;
219 }
220 wave_header_t header;
221 fread(&header, sizeof(header), 1, pb.source);
222 unsigned rate, channels;
223 pcm_sample_format_t format;
224 const char *error;
225 ret = wav_parse_header(&header, NULL, NULL, &channels, &rate, &format,
226 &error);
227 if (ret != EOK) {
228 printf("Error parsing wav header: %s.\n", error);
229 fclose(pb.source);
230 goto cleanup;
231 }
232
233 play(&pb, channels, rate, format);
234 fclose(pb.source);
235
236cleanup:
237 munmap(pb.buffer.base, pb.buffer.size);
238 audio_pcm_release_buffer(exch);
239close_session:
240 async_exchange_end(exch);
241 async_hangup(session);
242 return ret == EOK ? 0 : 1;
243}
244/**
245 * @}
246 */
Note: See TracBrowser for help on using the repository browser.