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 #ifdef HAVE_SYS_MMAN_H
18 #include <sys/types.h>
20 #include <sys/types.h>
26 extern char * get_path( char * filename
);
29 #define DEF_SZ 512 // default buffer size (in samples)
30 #define SHARED_FILE "mplayer-af_export" /* default file name
31 (relative to ~/.mplayer/ */
33 #define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
35 // Data for specific instances of this filter
36 typedef struct af_export_s
38 unsigned long long count
; // Used for sync
39 void* buf
[AF_NCH
]; // Buffers for storing the data before it is exported
40 int sz
; // Size of buffer in samples
41 int wi
; // Write index
42 int fd
; // File descriptor to shared memory area
43 char* filename
; // File to export data
44 void* mmap_area
; // MMap shared area
48 /* Initialization and runtime control
49 af audio filter instance
53 static int control(struct af_instance_s
* af
, int cmd
, void* arg
)
55 af_export_t
* s
= af
->setup
;
57 case AF_CONTROL_REINIT
:{
61 // Free previous buffers
62 if (s
->buf
&& s
->buf
[0])
65 // unmap previous area
67 munmap(s
->mmap_area
, SIZE_HEADER
+ (af
->data
->bps
*s
->sz
*af
->data
->nch
));
68 // close previous file descriptor
72 // Accept only int16_t as input format (which sucks)
73 af
->data
->rate
= ((af_data_t
*)arg
)->rate
;
74 af
->data
->nch
= ((af_data_t
*)arg
)->nch
;
75 af
->data
->format
= AF_FORMAT_S16_NE
;
78 // If buffer length isn't set, set it to the default value
82 // Allocate new buffers (as one continuous block)
83 s
->buf
[0] = calloc(s
->sz
*af
->data
->nch
, af
->data
->bps
);
85 af_msg(AF_MSG_FATAL
, "[export] Out of memory\n");
86 for(i
= 1; i
< af
->data
->nch
; i
++)
87 s
->buf
[i
] = s
->buf
[0] + i
*s
->sz
*af
->data
->bps
;
89 // Init memory mapping
90 s
->fd
= open(s
->filename
, O_RDWR
| O_CREAT
| O_TRUNC
, 0640);
91 af_msg(AF_MSG_INFO
, "[export] Exporting to file: %s\n", s
->filename
);
93 af_msg(AF_MSG_FATAL
, "[export] Could not open/create file: %s\n",
97 mapsize
= (SIZE_HEADER
+ (af
->data
->bps
* s
->sz
* af
->data
->nch
));
99 // grow file to needed size
100 for(i
= 0; i
< mapsize
; i
++){
102 write(s
->fd
, (void*) &null
, 1);
106 s
->mmap_area
= mmap(0, mapsize
, PROT_READ
|PROT_WRITE
,MAP_SHARED
, s
->fd
, 0);
107 if(s
->mmap_area
== NULL
)
108 af_msg(AF_MSG_FATAL
, "[export] Could not mmap file %s\n", s
->filename
);
109 af_msg(AF_MSG_INFO
, "[export] Memory mapped to file: %s (%p)\n",
110 s
->filename
, s
->mmap_area
);
113 *((int*)s
->mmap_area
) = af
->data
->nch
;
114 *((int*)s
->mmap_area
+ 1) = s
->sz
* af
->data
->bps
* af
->data
->nch
;
115 msync(s
->mmap_area
, mapsize
, MS_ASYNC
);
117 // Use test_output to return FALSE if necessary
118 return af_test_output(af
, (af_data_t
*)arg
);
120 case AF_CONTROL_COMMAND_LINE
:{
128 s
->filename
= get_path(SHARED_FILE
);
132 while((str
[i
]) && (str
[i
] != ':'))
138 s
->filename
= calloc(i
+ 1, sizeof(char));
139 memcpy(s
->filename
, str
, i
);
142 sscanf(str
+ i
+ 1, "%d", &(s
->sz
));
144 return af
->control(af
, AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
, &s
->sz
);
146 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_SET
:
147 s
->sz
= * (int *) arg
;
148 if((s
->sz
<= 0) || (s
->sz
> 2048))
149 af_msg( AF_MSG_ERROR
, "[export] Buffer size must be between"
153 case AF_CONTROL_EXPORT_SZ
| AF_CONTROL_GET
:
161 /* Free allocated memory and clean up other stuff too.
162 af audio filter instance
164 static void uninit( struct af_instance_s
* af
)
172 af_export_t
* s
= af
->setup
;
173 if (s
->buf
&& s
->buf
[0])
178 munmap(s
->mmap_area
, sizeof(af_export_t
));
191 /* Filter data through filter
192 af audio filter instance
195 static af_data_t
* play( struct af_instance_s
* af
, af_data_t
* data
)
197 af_data_t
* c
= data
; // Current working data
198 af_export_t
* s
= af
->setup
; // Setup for this instance
199 int16_t* a
= c
->audio
; // Incomming sound
200 int nch
= c
->nch
; // Number of channels
201 int len
= c
->len
/c
->bps
; // Number of sample in data chunk
202 int sz
= s
->sz
; // buffer size (in samples)
203 int flag
= 0; // Set to 1 if buffer is filled
208 for(ch
= 0; ch
< nch
; ch
++){
209 int wi
= s
->wi
; // Reset write index
210 int16_t* b
= s
->buf
[ch
]; // Current buffer
212 // Copy data to export buffers
213 for(i
= ch
; i
< len
; i
+= nch
){
215 if(wi
>= sz
){ // Don't write outside the end of the buffer
223 // Export buffer to mmaped area
225 // update buffer in mapped area
226 memcpy(s
->mmap_area
+ SIZE_HEADER
, s
->buf
[0], sz
* c
->bps
* nch
);
227 s
->count
++; // increment counter (to sync)
228 memcpy(s
->mmap_area
+ SIZE_HEADER
- sizeof(s
->count
),
229 &(s
->count
), sizeof(s
->count
));
232 // We don't modify data, just export it
236 /* Allocate memory and set function pointers
237 af audio filter instance
238 returns AF_OK or AF_ERROR
240 static int af_open( af_instance_t
* af
)
242 af
->control
= control
;
247 af
->data
= calloc(1, sizeof(af_data_t
));
248 af
->setup
= calloc(1, sizeof(af_export_t
));
249 if((af
->data
== NULL
) || (af
->setup
== NULL
))
252 ((af_export_t
*)af
->setup
)->filename
= get_path(SHARED_FILE
);
257 // Description of this filter
258 af_info_t af_info_export
= {
259 "Sound export filter",
261 "Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>",
267 #endif /*HAVE_SYS_MMAN_H*/