source: mainline/uspace/app/dplay/dplay.c@ 90f05b0f

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

Rename audio pcm interface.

  • Property mode set to 100644
File size: 6.4 KB
RevLine 
[a68a94e]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>
[90f05b0f]41#include <audio_pcm_iface.h>
[9d5244f]42#include <fibril_synch.h>
[a68a94e]43#include <stdio.h>
44#include <sys/mman.h>
[b499127]45#include <sys/time.h>
[a68a94e]46
[eaa1c28]47#include <stdio.h>
[7a5ab20]48#include <macros.h>
[eaa1c28]49
50#include "wave.h"
[a68a94e]51
52#define DEFAULT_DEVICE "/hw/pci0/00:01.0/sb16/dsp"
[9d5244f]53#define SUBBUFFERS 2
[a68a94e]54
[4bec78f]55typedef struct {
56 struct {
57 void *base;
58 size_t size;
59 unsigned id;
60 void* position;
61 } buffer;
62 FILE* source;
[9d5244f]63 volatile bool playing;
64 fibril_mutex_t mutex;
65 fibril_condvar_t cv;
66 async_exch_t *device;
[4bec78f]67} playback_t;
68
[9d5244f]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;
[c5c65b6]76 pb->buffer.position = NULL;
[9d5244f]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}
[4bec78f]83
[9d5244f]84
85static void device_event_callback(ipc_callid_t iid, ipc_call_t *icall, void* arg)
[4bec78f]86{
[68e005d]87 async_answer_0(iid, EOK);
88 playback_t *pb = arg;
89 const size_t buffer_part = pb->buffer.size / SUBBUFFERS;
[9d5244f]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 }
[c5c65b6]97 printf("+");
[9d5244f]98 const size_t bytes = fread(pb->buffer.position, sizeof(uint8_t),
99 buffer_part, pb->source);
[c5c65b6]100 bzero(pb->buffer.position + bytes, buffer_part - bytes);
101 pb->buffer.position += buffer_part;
102
[9d5244f]103 if (pb->buffer.position >= (pb->buffer.base + pb->buffer.size))
104 pb->buffer.position = pb->buffer.base;
[68e005d]105 async_answer_0(callid, EOK);
106 if (bytes == 0) {
[9d5244f]107 pb->playing = false;
108 fibril_condvar_signal(&pb->cv);
109 }
[4bec78f]110 }
111}
112
113
[9d5244f]114static void play(playback_t *pb, unsigned sampling_rate, unsigned sample_size,
115 unsigned channels, bool sign)
[b499127]116{
[4bec78f]117 assert(pb);
[9d5244f]118 assert(pb->device);
[4bec78f]119 pb->buffer.position = pb->buffer.base;
[c5c65b6]120 printf("Playing: %dHz, %d-bit %ssigned samples, %d channel(s).\n",
121 sampling_rate, sample_size, sign ? "": "un", channels);
[4bec78f]122 const size_t bytes = fread(pb->buffer.base, sizeof(uint8_t),
123 pb->buffer.size, pb->source);
124 if (bytes != pb->buffer.size)
[c5c65b6]125 bzero(pb->buffer.base + bytes, pb->buffer.size - bytes);
[4bec78f]126 printf("Buffer data ready.\n");
[9d5244f]127 fibril_mutex_lock(&pb->mutex);
[90f05b0f]128 int ret = audio_pcm_start_playback(pb->device, pb->buffer.id,
[9d5244f]129 SUBBUFFERS, sampling_rate, sample_size, channels, sign);
[b499127]130 if (ret != EOK) {
[9d5244f]131 fibril_mutex_unlock(&pb->mutex);
[b499127]132 printf("Failed to start playback: %s.\n", str_error(ret));
133 return;
134 }
[7a5ab20]135
[9d5244f]136 for (pb->playing = true; pb->playing;
[68e005d]137 fibril_condvar_wait(&pb->cv, &pb->mutex));
[b499127]138
[90f05b0f]139 audio_pcm_stop_playback(pb->device, pb->buffer.id);
[68e005d]140 fibril_condvar_wait(&pb->cv, &pb->mutex);
[c5c65b6]141 printf("\n");
[b499127]142}
143
[a68a94e]144int main(int argc, char *argv[])
145{
146 const char *device = DEFAULT_DEVICE;
[eaa1c28]147 const char *file;
148 switch (argc) {
149 case 2:
150 file = argv[1];
151 break;
152 case 3:
[a68a94e]153 device = argv[1];
[eaa1c28]154 file = argv[2];
155 break;
156 default:
157 printf("Usage: %s [device] file.\n", argv[0]);
158 return 1;
159 }
[a68a94e]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(
[4bec78f]170 EXCHANGE_SERIALIZE, pcm_handle, IPC_FLAG_BLOCKING);
[a68a94e]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) {
[c5c65b6]178 ret = EPARTY;
[a68a94e]179 printf("Failed to start session exchange.\n");
[c5c65b6]180 goto close_session;
[a68a94e]181 }
[4bec78f]182 const char* info = NULL;
[90f05b0f]183 ret = audio_pcm_get_info_str(exch, &info);
[a68a94e]184 if (ret != EOK) {
185 printf("Failed to get PCM info.\n");
[c5c65b6]186 goto close_session;
[a68a94e]187 }
188 printf("Playing on %s.\n", info);
189 free(info);
190
[9d5244f]191 playback_t pb;
192 playback_initialize(&pb, exch);
193
[90f05b0f]194 ret = audio_pcm_get_buffer(pb.device, &pb.buffer.base,
[4bec78f]195 &pb.buffer.size, &pb.buffer.id, device_event_callback, &pb);
[a68a94e]196 if (ret != EOK) {
197 printf("Failed to get PCM buffer: %s.\n", str_error(ret));
[c5c65b6]198 goto close_session;
[a68a94e]199 }
[4bec78f]200 printf("Buffer (%u): %p %zu.\n", pb.buffer.id, pb.buffer.base,
201 pb.buffer.size);
[9d5244f]202 uintptr_t ptr = 0;
203 as_get_physical_mapping(pb.buffer.base, &ptr);
204 printf("buffer mapped at %x.\n", ptr);
[a68a94e]205
[4bec78f]206 pb.source = fopen(file, "rb");
207 if (pb.source == NULL) {
[c5c65b6]208 ret = ENOENT;
[eaa1c28]209 printf("Failed to open %s.\n", file);
[c5c65b6]210 goto cleanup;
[eaa1c28]211 }
212 wave_header_t header;
[4bec78f]213 fread(&header, sizeof(header), 1, pb.source);
[eaa1c28]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);
[4bec78f]221 fclose(pb.source);
[c5c65b6]222 goto cleanup;
[eaa1c28]223 }
224
[9d5244f]225 play(&pb, rate, sample_size, channels, sign);
[ef246b9]226 fclose(pb.source);
[a68a94e]227
[c5c65b6]228cleanup:
[4bec78f]229 munmap(pb.buffer.base, pb.buffer.size);
[90f05b0f]230 audio_pcm_release_buffer(exch, pb.buffer.id);
[c5c65b6]231close_session:
[a68a94e]232 async_exchange_end(exch);
233 async_hangup(session);
[c5c65b6]234 return ret == EOK ? 0 : 1;
[a68a94e]235}
[b499127]236/**
237 * @}
[a68a94e]238 */
Note: See TracBrowser for help on using the repository browser.