2 * This audio filter exports the incoming signal to other processes
3 * using memory mapping. The memory mapped area contains a header:
6 * unsigned long long counter (updated every time the contents of
8 * the rest is payload (non-interleaved).
10 * This file is part of MPlayer.
12 * MPlayer is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * MPlayer is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <sys/types.h>
36 #include <sys/types.h>
43 #define DEF_SZ 512 // default buffer size (in samples)
44 #define SHARED_FILE "mplayer-af_export" /* default file name
45 (relative to ~/.mplayer/ */
47 #define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
49 // Data for specific instances of this filter
50 typedef struct af_export_s
52 unsigned long long count
; // Used for sync
53 void* buf
[AF_NCH
]; // Buffers for storing the data before it is exported
54 int sz
; // Size of buffer in samples
55 int wi
; // Write index
56 int fd
; // File descriptor to shared memory area
57 char* filename
; // File to export data
58 uint8_t *mmap_area
; // MMap shared area
62 /* Initialization and runtime control
63 af audio filter instance
67 static int control(struct af_instance_s
* af
, int cmd
, void* arg
)
69 af_export_t
* s
= af
->setup
;
71 case AF_CONTROL_REINIT
:{
75 // Free previous buffers
79 // unmap previous area
81 munmap(s
->mmap_area
, SIZE_HEADER
+ (af
->data
->bps
*s
->sz
*af
->data
->nch
));
82 // close previous file descriptor
86 // Accept only int16_t as input format (which sucks)
87 af
->data
->rate
= ((af_data_t
*)arg
)->rate
;
88 af
->data
->nch
= ((af_data_t
*)arg
)->nch
;
89 af
->data
->format
= AF_FORMAT_S16_NE
;
92 // If buffer length isn't set, set it to the default value
96 // Allocate new buffers (as one continuous block)
97 s
->buf
[0] = calloc(s
->sz
*af
->data
->nch
, af
->data
->bps
);
99 mp_msg(MSGT_AFILTER
, MSGL_FATAL
, "[export] Out of memory\n");
100 for(i
= 1; i
< af
->data
->nch
; i
++)
101 s
->buf
[i
] = (uint8_t *)s
->buf
[0] + i
*s
->sz
*af
->data
->bps
;
103 // Init memory mapping
104 s
->fd
= open(s
->filename
, O_RDWR
| O_CREAT
| O_TRUNC
, 0640);
105 mp_msg(MSGT_AFILTER
, MSGL_INFO
, "[export] Exporting to file: %s\n", s
->filename
);
107 mp_msg(MSGT_AFILTER
, MSGL_FATAL
, "[export] Could not open/create file: %s\n",
111 mapsize
= (SIZE_HEADER
+ (af
->data
->bps
* s
->sz
* af
->data
->nch
));
113 // grow file to needed size
114 for(i
= 0; i
< mapsize
; i
++){
116 write(s
->fd
, (void*) &null
, 1);
120 s
->mmap_area
= mmap(0, mapsize
, PROT_READ
|PROT_WRITE
,MAP_SHARED
, s
->fd
, 0);
121 if(s
->mmap_area
== NULL
)
122 mp_msg(MSGT_AFILTER
, MSGL_FATAL
, "[export] Could not mmap file %s\n", s
->filename
);
123 mp_msg(MSGT_AFILTER
, MSGL_INFO
, "[export] Memory mapped to file: %s (%p)\n",
124 s
->filename
, s
->mmap_area
);
127 *((int*)s
->mmap_area
) = af
->data
->nch
;
128 *((int*)s
->mmap_area
+ 1) = s
->sz
* af
->data
->bps
* af
->data
->nch
;
129 msync(s
->mmap_area
, mapsize
, MS_ASYNC
);
131 // Use test_output to return FALSE if necessary
132 return af_test_output(af
, (af_data_t
*)arg
);
134 case AF_CONTROL_COMMAND_LINE
:{
141 s
->filename
= get_path(SHARED_FILE
);
145 while((str
[i
]) && (str
[i
] != ':'))
150 s
->filename
= calloc(i
+ 1, 1);
151 memcpy(s
->filename
, str
, i
);
154 sscanf(str
+ i
+ 1, "%d", &(s
->sz
));
156 return af
->control(af
, AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
, &s
->sz
);
158 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
:
159 s
->sz
= * (int *) arg
;
160 if((s
->sz
<= 0) || (s
->sz
> 2048))
161 mp_msg(MSGT_AFILTER
, MSGL_ERR
, "[export] Buffer size must be between"
165 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_GET
:
173 /* Free allocated memory and clean up other stuff too.
174 af audio filter instance
176 static void uninit( struct af_instance_s
* af
)
182 af_export_t
* s
= af
->setup
;
188 munmap(s
->mmap_area
, sizeof(af_export_t
));
200 /* Filter data through filter
201 af audio filter instance
204 static af_data_t
* play( struct af_instance_s
* af
, af_data_t
* data
)
206 af_data_t
* c
= data
; // Current working data
207 af_export_t
* s
= af
->setup
; // Setup for this instance
208 int16_t* a
= c
->audio
; // Incomming sound
209 int nch
= c
->nch
; // Number of channels
210 int len
= c
->len
/c
->bps
; // Number of sample in data chunk
211 int sz
= s
->sz
; // buffer size (in samples)
212 int flag
= 0; // Set to 1 if buffer is filled
217 for(ch
= 0; ch
< nch
; ch
++){
218 int wi
= s
->wi
; // Reset write index
219 int16_t* b
= s
->buf
[ch
]; // Current buffer
221 // Copy data to export buffers
222 for(i
= ch
; i
< len
; i
+= nch
){
224 if(wi
>= sz
){ // Don't write outside the end of the buffer
232 // Export buffer to mmaped area
234 // update buffer in mapped area
235 memcpy(s
->mmap_area
+ SIZE_HEADER
, s
->buf
[0], sz
* c
->bps
* nch
);
236 s
->count
++; // increment counter (to sync)
237 memcpy(s
->mmap_area
+ SIZE_HEADER
- sizeof(s
->count
),
238 &(s
->count
), sizeof(s
->count
));
241 // We don't modify data, just export it
245 /* Allocate memory and set function pointers
246 af audio filter instance
247 returns AF_OK or AF_ERROR
249 static int af_open( af_instance_t
* af
)
251 af
->control
= control
;
255 af
->data
= calloc(1, sizeof(af_data_t
));
256 af
->setup
= calloc(1, sizeof(af_export_t
));
257 if((af
->data
== NULL
) || (af
->setup
== NULL
))
260 ((af_export_t
*)af
->setup
)->filename
= get_path(SHARED_FILE
);
265 // Description of this filter
266 af_info_t af_info_export
= {
267 "Sound export filter",
269 "Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>",