source: mainline/uspace/app/wavplay/drec.c@ 64ce0c1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 64ce0c1 was 33b8d024, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

Remove const qualifier from the argument of free() and realloc(),
as well as in numerous other variables that hold ownership of memory.

By convention, a pointer that holds ownership is _never_ qualified by const.
This is reflected in the standard type signature of free() and realloc().
Allowing const pointers to hold ownership may seem superficially convenient,
but is actually quite confusing to experienced C programmers.

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