root/branches/libfreebob-1.0/src/libfreebobstreaming/freebob_connections.c

Revision 328, 9.5 kB (checked in by wagi, 15 years ago)

2006-11-20 Daniel Wagner <wagi@newton.monom.org>

  • freebob_streaming_start: Reset the playback ringbuffer before calling
    freebob_streaming_start.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  *   FreeBoB Streaming API
3  *   FreeBoB = Firewire (pro-)audio for linux
4  *
5  *   http://freebob.sf.net
6  *
7  *   Copyright (C) 2005 Pieter Palmers <pieterpalmers@users.sourceforge.net>
8  *
9  *   This program is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU General Public License as published by
11  *   the Free Software Foundation; either version 2 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This program is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with this program; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  *
24  *
25  */
26
27 /* freebob_connections.c
28  *
29  * Connection handling
30  *
31  */
32 #include <libraw1394/raw1394.h>
33 #include <libiec61883/iec61883.h>
34
35 #include "libfreebob/freebob_streaming.h"
36 #include "freebob_streaming_private.h"
37 #include "freebob_connections.h"
38 #include "freebob_debug.h"
39
40 raw1394handle_t freebob_open_raw1394 (int port)
41 {
42         raw1394handle_t raw1394_handle;
43         int ret;
44         int stale_port_info;
45  
46         /* open the connection to libraw1394 */
47         raw1394_handle = raw1394_new_handle ();
48         if (!raw1394_handle) {
49                 if (errno == 0) {
50                         printError("This version of libraw1394 is "
51                                     "incompatible with your kernel\n");
52                 } else {
53                         printError("Could not create libraw1394 "
54                                     "handle: %s\n", strerror (errno));
55                 }
56
57                 return NULL;
58         }
59  
60         /* set the port we'll be using */
61         stale_port_info = 1;
62         do {
63                 ret = raw1394_get_port_info (raw1394_handle, NULL, 0);
64                 if (ret <= port) {
65                         printError("IEEE394 port %d is not available\n", port);
66                         raw1394_destroy_handle (raw1394_handle);
67                         return NULL;
68                 }
69  
70                 ret = raw1394_set_port (raw1394_handle, port);
71                 if (ret == -1) {
72                         if (errno != ESTALE) {
73                                 printError("Couldn't use IEEE394 port %d: %s\n",
74                                             port, strerror (errno));
75                                 raw1394_destroy_handle (raw1394_handle);
76                                 return NULL;
77                         }
78                 }
79                 else {
80                         stale_port_info = 0;
81                 }
82         } while (stale_port_info);
83  
84         return raw1394_handle;
85 }
86
87 int freebob_streaming_reset_connection(freebob_device_t * dev, freebob_connection_t *connection) {
88         int s=0;
89         int err=0;
90        
91         assert(dev);
92         assert(connection);
93        
94         printEnter();
95        
96         for (s=0;s<connection->nb_streams;s++) {
97                 err=freebob_streaming_reset_stream(dev,&connection->streams[s]);
98                 if(err) {
99                         printError("Could not reset stream %d",s);
100                         break;
101                 }
102                
103         }
104        
105         // reset the event buffer, discard all content
106         freebob_ringbuffer_reset(connection->event_buffer);
107        
108         // reset the timestamp buffer, discard all content
109         freebob_ringbuffer_reset(connection->timestamp_buffer);
110        
111         // reset the event counter
112         connection->status.events=0;
113        
114         // reset the boundary counter
115         connection->status.frames_left = 0;
116        
117         // reset the counters
118         connection->status.xruns = 0;
119         connection->status.packets=0;   
120
121 #ifdef DEBUG
122         connection->status.total_packets_prev=0;
123 #endif
124
125         connection->status.dropped=0;
126
127         // make sure the connection is polled next time
128         if(connection->pfd) { // this can be called before everything is init'ed
129                 connection->pfd->events=POLLIN;
130         }
131
132         printExit();
133        
134         return 0;
135        
136 }
137
138 int freebob_streaming_init_connection(freebob_device_t * dev, freebob_connection_t *connection) {
139         int err=0;
140         int s=0;
141        
142         connection->status.frames_left=0;
143        
144         connection->parent=dev;
145                
146         // create raw1394 handles
147         connection->raw_handle=freebob_open_raw1394(connection->spec.port);
148         if (!connection->raw_handle) {
149                 printError("Could not get raw1394 handle\n");
150                 return -ENOMEM;
151         }
152         raw1394_set_userdata(connection->raw_handle, (void *)connection);
153        
154         connection->iso.speed = RAW1394_ISO_SPEED_400;
155        
156         connection->iso.bandwidth=-1;
157         connection->iso.startcycle=-1;
158        
159         // allocate the event ringbuffer
160         if( !(connection->event_buffer=freebob_ringbuffer_create(
161                         (connection->spec.dimension * dev->options.nb_buffers * dev->options.period_size) * sizeof(quadlet_t)))) {
162                 printError("Could not allocate memory event ringbuffer");
163                 return -ENOMEM;
164                        
165         }
166         // allocate the temporary cluster buffer
167         if( !(connection->cluster_buffer=(char *)calloc(connection->spec.dimension,sizeof(quadlet_t)))) {
168                 printError("Could not allocate temporary cluster buffer");
169                 freebob_ringbuffer_free(connection->event_buffer);
170                 return -ENOMEM;
171         }
172        
173         // allocate the timestamp buffer
174         if( !(connection->timestamp_buffer=freebob_ringbuffer_create(TIMESTAMP_BUFFER_SIZE * sizeof(freebob_timestamp_t)))) {
175                 printError("Could not allocate timestamp ringbuffer");
176                 freebob_ringbuffer_free(connection->event_buffer);
177                 free(connection->cluster_buffer);
178                 return -ENOMEM;
179         }
180        
181         connection->total_delay=0;
182        
183         /*
184          * init the streams this connection is composed of
185          */
186         assert(connection->spec.stream_info);
187         connection->nb_streams=connection->spec.stream_info->nb_streams;
188        
189         connection->streams=calloc(connection->nb_streams, sizeof(freebob_stream_t));
190        
191         if(!connection->streams) {
192                 printError("Could not allocate memory for streams");
193                 free(connection->cluster_buffer);
194                 freebob_ringbuffer_free(connection->event_buffer);
195                 return -ENOMEM;
196         }
197                
198         err=0;
199         for (s=0;s<connection->nb_streams;s++) {
200                 err=freebob_streaming_init_stream(dev,&connection->streams[s],connection->spec.stream_info->streams[s]);
201                 if(err) {
202                         printError("Could not init stream %d",s);
203                         break;
204                 }
205                
206                 // set the stream parent relation
207                 connection->streams[s].parent=connection;
208                
209                 // register the stream in the stream list used for reading out
210                 if(connection->spec.direction==FREEBOB_CAPTURE) {
211                         freebob_streaming_register_capture_stream(dev, &connection->streams[s]);
212                 } else {
213                         freebob_streaming_register_playback_stream(dev, &connection->streams[s]);
214                 }
215         }       
216         if (err) {
217                 debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up streams...\n");
218                 while(s--) { // TODO: check if this counts correctly
219                         debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up stream %d...\n",s);
220                         freebob_streaming_cleanup_stream(dev, &connection->streams[s]);
221                 }
222                
223                 free(connection->streams);
224                 free(connection->cluster_buffer);
225                 freebob_ringbuffer_free(connection->event_buffer);
226                 freebob_ringbuffer_free(connection->timestamp_buffer);
227                
228                 return err;             
229         }
230        
231         // FIXME: a flaw of the current approach is that a spec->stream_info isn't a valid pointer
232         connection->spec.stream_info=NULL;
233        
234         // put the connection into a know state
235         freebob_streaming_reset_connection(dev, connection);
236
237         return 0;
238 }
239
240 int freebob_streaming_cleanup_connection(freebob_device_t * dev, freebob_connection_t *connection) {
241
242         unsigned int s;
243        
244         for (s=0;s<connection->nb_streams;s++) {
245                 debugPrint(DEBUG_LEVEL_STARTUP,"  Cleaning up stream %d...\n",s);
246                 freebob_streaming_cleanup_stream(dev, &connection->streams[s]);
247         }
248        
249         free(connection->streams);
250         free(connection->cluster_buffer);
251         freebob_ringbuffer_free(connection->event_buffer);
252         freebob_ringbuffer_free(connection->timestamp_buffer);
253        
254         raw1394_destroy_handle(connection->raw_handle);
255 /*
256         assert(connection->status.packet_info_table);
257         free(connection->status.packet_info_table);
258         connection->status.packet_info_table=NULL;
259 */
260        
261         return 0;
262        
263 }
264
265 /**
266  * Initializes a stream_t based upon an stream_info_t
267  */
268 int freebob_streaming_init_stream(freebob_device_t* dev, freebob_stream_t *dst, freebob_stream_spec_t *src) {
269         assert(dev);
270         assert(dst);
271         assert(src);
272        
273         memcpy(&dst->spec,src,sizeof(freebob_stream_spec_t));
274        
275         // allocate the ringbuffer
276         // the lock free ringbuffer needs one extra frame
277         // it can only be filled to size-1 bytes
278
279         // keep the ringbuffer aligned by adding sizeof(sample_t) bytes instead of just 1
280         int buffer_size_frames=dev->options.nb_buffers*dev->options.period_size+1;
281         dst->buffer=freebob_ringbuffer_create(buffer_size_frames*sizeof(freebob_sample_t));
282        
283        
284         // initialize the decoder stuff to use the per-stream read functions
285         dst->buffer_type=freebob_buffer_type_per_stream;
286         dst->user_buffer=NULL;
287        
288         // create any data structures for the decode buffers
289         freebob_streaming_set_stream_buffer(dev, dst, NULL, freebob_buffer_type_per_stream);
290        
291         // no other init needed
292         return 0;
293        
294 }
295
296 /**
297   * destroys a stream_t
298   */
299 void freebob_streaming_cleanup_stream(freebob_device_t* dev, freebob_stream_t *dst) {
300         assert(dev);
301         assert(dst);
302         assert(dst->user_buffer);
303        
304         freebob_streaming_free_stream_buffer(dev, dst);
305                
306         freebob_ringbuffer_free(dst->buffer);
307         return;
308        
309 }
310
311 /**
312   * puts a stream into a known state
313   */
314 int freebob_streaming_reset_stream(freebob_device_t* dev, freebob_stream_t *dst) {
315         assert(dev);
316         assert(dst);
317        
318         freebob_ringbuffer_reset(dst->buffer);
319         return 0;
320 }
321
322
323 int freebob_streaming_prefill_stream(freebob_device_t* dev, freebob_stream_t *stream) {
324         assert(stream);
325         int towrite=0;
326         int written=0;
327         char *buffer=NULL;
328                        
329         switch(stream->spec.format) {
330                 case IEC61883_STREAM_TYPE_MBLA:
331                         towrite=dev->options.period_size*dev->options.nb_buffers*sizeof(freebob_sample_t);
332                        
333                         // calloc clears the allocated memory
334                         buffer=calloc(1,towrite);
335                         written=freebob_ringbuffer_write(stream->buffer,(char *)buffer,towrite);
336                         free(buffer);
337                        
338                         if(written != towrite) {
339                                 assert(!"Could not prefill the playback stream ringbuffer, which should have been empty.");
340                                 printError("Could not prefill the buffer. Written (%d/%d) of (%d/%d) bytes/frames\n",
341                                         written,written/sizeof(freebob_sample_t),towrite,towrite/sizeof(freebob_sample_t));
342                                 return -1;
343                         }
344                 break;
345                 case IEC61883_STREAM_TYPE_MIDI: // no prefill nescessary
346                 case IEC61883_STREAM_TYPE_SPDIF: // unsupported
347                 default:
348                 break;
349         }
350         return 0;
351 }
Note: See TracBrowser for help on using the browser.