source: mainline/uspace/app/wavplay/drec.c

Last change on this file was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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