1 /* This audio filter exports the incomming signal to other processes
2 using memory mapping. Memory mapped area contains a header:
5 unsigned long long counter (updated every time the contents of
7 the rest is payload (non-interleaved).
17 #include <sys/types.h>
19 #include <sys/types.h>
26 #define DEF_SZ 512 // default buffer size (in samples)
27 #define SHARED_FILE "mplayer-af_export" /* default file name
28 (relative to ~/.mplayer/ */
30 #define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
32 // Data for specific instances of this filter
33 typedef struct af_export_s
35 unsigned long long count
; // Used for sync
36 void* buf
[AF_NCH
]; // Buffers for storing the data before it is exported
37 int sz
; // Size of buffer in samples
38 int wi
; // Write index
39 int fd
; // File descriptor to shared memory area
40 char* filename
; // File to export data
41 void* mmap_area
; // MMap shared area
45 /* Initialization and runtime control
46 af audio filter instance
50 static int control(struct af_instance_s
* af
, int cmd
, void* arg
)
52 af_export_t
* s
= af
->setup
;
54 case AF_CONTROL_REINIT
:{
58 // Free previous buffers
59 if (s
->buf
&& s
->buf
[0])
62 // unmap previous area
64 munmap(s
->mmap_area
, SIZE_HEADER
+ (af
->data
->bps
*s
->sz
*af
->data
->nch
));
65 // close previous file descriptor
69 // Accept only int16_t as input format (which sucks)
70 af
->data
->rate
= ((af_data_t
*)arg
)->rate
;
71 af
->data
->nch
= ((af_data_t
*)arg
)->nch
;
72 af
->data
->format
= AF_FORMAT_S16_NE
;
75 // If buffer length isn't set, set it to the default value
79 // Allocate new buffers (as one continuous block)
80 s
->buf
[0] = calloc(s
->sz
*af
->data
->nch
, af
->data
->bps
);
82 af_msg(AF_MSG_FATAL
, "[export] Out of memory\n");
83 for(i
= 1; i
< af
->data
->nch
; i
++)
84 s
->buf
[i
] = s
->buf
[0] + i
*s
->sz
*af
->data
->bps
;
86 // Init memory mapping
87 s
->fd
= open(s
->filename
, O_RDWR
| O_CREAT
| O_TRUNC
, 0640);
88 af_msg(AF_MSG_INFO
, "[export] Exporting to file: %s\n", s
->filename
);
90 af_msg(AF_MSG_FATAL
, "[export] Could not open/create file: %s\n",
94 mapsize
= (SIZE_HEADER
+ (af
->data
->bps
* s
->sz
* af
->data
->nch
));
96 // grow file to needed size
97 for(i
= 0; i
< mapsize
; i
++){
99 write(s
->fd
, (void*) &null
, 1);
103 s
->mmap_area
= mmap(0, mapsize
, PROT_READ
|PROT_WRITE
,MAP_SHARED
, s
->fd
, 0);
104 if(s
->mmap_area
== NULL
)
105 af_msg(AF_MSG_FATAL
, "[export] Could not mmap file %s\n", s
->filename
);
106 af_msg(AF_MSG_INFO
, "[export] Memory mapped to file: %s (%p)\n",
107 s
->filename
, s
->mmap_area
);
110 *((int*)s
->mmap_area
) = af
->data
->nch
;
111 *((int*)s
->mmap_area
+ 1) = s
->sz
* af
->data
->bps
* af
->data
->nch
;
112 msync(s
->mmap_area
, mapsize
, MS_ASYNC
);
114 // Use test_output to return FALSE if necessary
115 return af_test_output(af
, (af_data_t
*)arg
);
117 case AF_CONTROL_COMMAND_LINE
:{
125 s
->filename
= get_path(SHARED_FILE
);
129 while((str
[i
]) && (str
[i
] != ':'))
135 s
->filename
= calloc(i
+ 1, 1);
136 memcpy(s
->filename
, str
, i
);
139 sscanf(str
+ i
+ 1, "%d", &(s
->sz
));
141 return af
->control(af
, AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
, &s
->sz
);
143 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
:
144 s
->sz
= * (int *) arg
;
145 if((s
->sz
<= 0) || (s
->sz
> 2048))
146 af_msg( AF_MSG_ERROR
, "[export] Buffer size must be between"
150 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_GET
:
158 /* Free allocated memory and clean up other stuff too.
159 af audio filter instance
161 static void uninit( struct af_instance_s
* af
)
169 af_export_t
* s
= af
->setup
;
170 if (s
->buf
&& s
->buf
[0])
175 munmap(s
->mmap_area
, sizeof(af_export_t
));
188 /* Filter data through filter
189 af audio filter instance
192 static af_data_t
* play( struct af_instance_s
* af
, af_data_t
* data
)
194 af_data_t
* c
= data
; // Current working data
195 af_export_t
* s
= af
->setup
; // Setup for this instance
196 int16_t* a
= c
->audio
; // Incomming sound
197 int nch
= c
->nch
; // Number of channels
198 int len
= c
->len
/c
->bps
; // Number of sample in data chunk
199 int sz
= s
->sz
; // buffer size (in samples)
200 int flag
= 0; // Set to 1 if buffer is filled
205 for(ch
= 0; ch
< nch
; ch
++){
206 int wi
= s
->wi
; // Reset write index
207 int16_t* b
= s
->buf
[ch
]; // Current buffer
209 // Copy data to export buffers
210 for(i
= ch
; i
< len
; i
+= nch
){
212 if(wi
>= sz
){ // Don't write outside the end of the buffer
220 // Export buffer to mmaped area
222 // update buffer in mapped area
223 memcpy(s
->mmap_area
+ SIZE_HEADER
, s
->buf
[0], sz
* c
->bps
* nch
);
224 s
->count
++; // increment counter (to sync)
225 memcpy(s
->mmap_area
+ SIZE_HEADER
- sizeof(s
->count
),
226 &(s
->count
), sizeof(s
->count
));
229 // We don't modify data, just export it
233 /* Allocate memory and set function pointers
234 af audio filter instance
235 returns AF_OK or AF_ERROR
237 static int af_open( af_instance_t
* af
)
239 af
->control
= control
;
243 af
->data
= calloc(1, sizeof(af_data_t
));
244 af
->setup
= calloc(1, sizeof(af_export_t
));
245 if((af
->data
== NULL
) || (af
->setup
== NULL
))
248 ((af_export_t
*)af
->setup
)->filename
= get_path(SHARED_FILE
);
253 // Description of this filter
254 af_info_t af_info_export
= {
255 "Sound export filter",
257 "Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>",