source: mainline/uspace/app/wavplay/dplay.c@ c5cbc1b7

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

Integrate dplay into wavplay.

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