source: mainline/uspace/app/wavplay/drec.c@ 63d46341

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63d46341 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * Copyright (c) 2013 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 wavplay
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 <audio_pcm_iface.h>
40#include <pcm/format.h>
41#include <stdio.h>
42#include <as.h>
43#include <inttypes.h>
44#include <str.h>
45
46#include "wave.h"
47#include "drec.h"
48
49
50#define BUFFER_PARTS 16
51
52/** Recording format */
53static const pcm_format_t format = {
54 .sampling_rate = 44100,
55 .channels = 2,
56 .sample_format = PCM_SAMPLE_SINT16_LE,
57};
58
59/** Recording helper structure */
60typedef struct {
61 struct {
62 void *base;
63 size_t size;
64 unsigned id;
65 void *position;
66 } buffer;
67 FILE *file;
68 audio_pcm_sess_t *device;
69} record_t;
70
71/**
72 * Initialize recording helper structure.
73 * @param rec Recording structure.
74 * @param sess Session to IPC device.
75 */
76static void record_initialize(record_t *rec, audio_pcm_sess_t *sess)
77{
78 assert(sess);
79 assert(rec);
80 rec->buffer.base = NULL;
81 rec->buffer.size = 0;
82 rec->buffer.position = NULL;
83 rec->file = NULL;
84 rec->device = sess;
85}
86
87/** Recording callback.
88 *
89 * Writes recorded data.
90 *
91 * @param icall Poitner to IPC call structure.
92 * @param arg Argument. Poitner to recording helper structure.
93 *
94 */
95static void device_event_callback(ipc_call_t *icall, void *arg)
96{
97 async_answer_0(icall, EOK);
98 record_t *rec = arg;
99 const size_t buffer_part = rec->buffer.size / BUFFER_PARTS;
100 bool record = true;
101
102 while (record) {
103 ipc_call_t call;
104 async_get_call(&call);
105
106 switch (IPC_GET_IMETHOD(call)) {
107 case PCM_EVENT_CAPTURE_TERMINATED:
108 printf("Recording terminated\n");
109 record = false;
110 break;
111 case PCM_EVENT_FRAMES_CAPTURED:
112 printf("%" PRIun " frames\n", IPC_GET_ARG1(call));
113 break;
114 default:
115 printf("Unknown event %" PRIun ".\n", IPC_GET_IMETHOD(call));
116 async_answer_0(&call, ENOTSUP);
117 continue;
118 }
119
120 if (!record) {
121 async_answer_0(&call, EOK);
122 break;
123 }
124
125 /* Write directly from device buffer to file */
126 const size_t bytes = fwrite(rec->buffer.position,
127 sizeof(uint8_t), buffer_part, rec->file);
128 printf("%zu ", bytes);
129 rec->buffer.position += buffer_part;
130
131 if (rec->buffer.position >= (rec->buffer.base + rec->buffer.size))
132 rec->buffer.position = rec->buffer.base;
133 async_answer_0(&call, EOK);
134 }
135}
136
137/**
138 * Start fragment based recording.
139 * @param rec Recording helper structure.
140 * @param f PCM format
141 */
142static void record_fragment(record_t *rec, pcm_format_t f)
143{
144 assert(rec);
145 assert(rec->device);
146 errno_t ret = audio_pcm_register_event_callback(rec->device,
147 device_event_callback, rec);
148 if (ret != EOK) {
149 printf("Failed to register for events: %s.\n", str_error(ret));
150 return;
151 }
152 rec->buffer.position = rec->buffer.base;
153 printf("Recording: %dHz, %s, %d channel(s).\n", f.sampling_rate,
154 pcm_sample_format_str(f.sample_format), f.channels);
155 const unsigned frames =
156 pcm_format_size_to_frames(rec->buffer.size / BUFFER_PARTS, &f);
157 ret = audio_pcm_start_capture_fragment(rec->device,
158 frames, f.channels, f.sampling_rate, f.sample_format);
159 if (ret != EOK) {
160 printf("Failed to start recording: %s.\n", str_error(ret));
161 return;
162 }
163
164 getchar();
165 printf("\n");
166 audio_pcm_stop_capture(rec->device);
167 /* XXX Control returns even before we can be sure callbacks finished */
168 printf("Delay before playback termination\n");
169 async_usleep(1000000);
170 printf("Terminate playback\n");
171}
172
173/**
174 * Record directly from a device to a file.
175 * @param device The device.
176 * @param file The file.
177 * @return 0 on succes, non-zero on failure.
178 */
179int drecord(const char *device, const char *file)
180{
181 errno_t ret = EOK;
182 audio_pcm_sess_t *session = NULL;
183 sysarg_t val;
184 if (str_cmp(device, "default") == 0) {
185 session = audio_pcm_open_default();
186 } else {
187 session = audio_pcm_open(device);
188 }
189 if (!session) {
190 printf("Failed to connect to device %s.\n", device);
191 return 1;
192 }
193 printf("Recording on device: %s.\n", device);
194 ret = audio_pcm_query_cap(session, AUDIO_CAP_CAPTURE, &val);
195 if (ret != EOK || !val) {
196 printf("Device %s does not support recording\n", device);
197 ret = ENOTSUP;
198 goto close_session;
199 }
200
201 char *info = NULL;
202 ret = audio_pcm_get_info_str(session, &info);
203 if (ret != EOK) {
204 printf("Failed to get PCM info.\n");
205 goto close_session;
206 }
207 printf("Capturing on %s.\n", info);
208 free(info);
209
210 record_t rec;
211 record_initialize(&rec, session);
212
213 ret = audio_pcm_get_buffer(rec.device, &rec.buffer.base,
214 &rec.buffer.size);
215 if (ret != EOK) {
216 printf("Failed to get PCM buffer: %s.\n", str_error(ret));
217 goto close_session;
218 }
219 printf("Buffer: %p %zu.\n", rec.buffer.base, rec.buffer.size);
220
221 rec.file = fopen(file, "w");
222 if (rec.file == NULL) {
223 ret = ENOENT;
224 printf("Failed to open file: %s.\n", file);
225 goto cleanup;
226 }
227
228 wave_header_t header;
229 fseek(rec.file, sizeof(header), SEEK_SET);
230 if (ret != EOK) {
231 printf("Error parsing wav header\n");
232 goto cleanup;
233 }
234 ret = audio_pcm_query_cap(rec.device, AUDIO_CAP_INTERRUPT, &val);
235 if (ret == EOK && val)
236 record_fragment(&rec, format);
237 else
238 printf("Recording method is not supported");
239 //TODO consider buffer position interface
240
241 wav_init_header(&header, format, ftell(rec.file) - sizeof(header));
242 fseek(rec.file, 0, SEEK_SET);
243 fwrite(&header, sizeof(header), 1, rec.file);
244
245cleanup:
246 fclose(rec.file);
247 as_area_destroy(rec.buffer.base);
248 audio_pcm_release_buffer(rec.device);
249close_session:
250 audio_pcm_close(session);
251 return ret == EOK ? 0 : 1;
252}
253/**
254 * @}
255 */
Note: See TracBrowser for help on using the repository browser.