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

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

Rename audio nodes: (mixer, dsp) ⇒ (control, pcm).

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