Logo Studenta

UC3M _Universidad Carlos III de Madrid_ _ Máster en Ingeniería a de las Telecomunicaciones _ sistemas multimedia avanzados_ clases de ayuda _ practicas

Esta es una vista previa del archivo. Inicie sesión para ver el archivo original

practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/check-list_APELLIDO_miembro1.APELLIDO_miembro2_v2.docxPruebas práctica 1 de SMA 			(versión 2)
[Nombre y apellido de los miembros del grupo]
Indique SI o NO en la columna de la derecha a cada pregunta sobre su práctica (resultado de sus pruebas en los laboratorios del Departamento de Ingeniería Telemática en Leganés).
Pruebas de audio
Básicas para aprobar
	1. ¿Se escucha correctamente durante al menos 1 minuto en formato 8 bits?
	
	2. ¿Se escucha correctamente durante al menos 1 minuto en formato 16 bits?
a. ¿Se escucha correctamente con –l40?
b. ¿Con -l120?
	
	3. Si se ejecuta en ambos extremos con –k3000 ¿funciona (sin segmentation fault, vaciados de buffer) y se nota un retardo apreciable en la reproducción (del orden de 3 segundos)? 
	
Avanzadas
	4. ¿Funciona sin pérdidas de paquetes apreciables con –kxx tal que sólo se utiliza 1 paquete de buffer?
Si no funciona con 1 paquete de buffer, indique cuál es el valor mínimo de –k (número mínimo de paquetes de buffer) con los que funciona de forma correcta. 
	
Capture el tráfico con rtpdump (básicas)
	5. rtpdump identifica correctamente a los paquetes como RTP. 
	
	Los paquetes tienen el tamaño esperado (12 + un número potencia de 2)
	
	El número de secuencia se incrementa de uno en uno
	
	El timestamp se incrementa en el número de muestras contenidas en cada paquete
	
Mire las trazas de first
(mire el documento ‘Testing conf’ en Aula Global, ejecute en first ‘strace –tt –o trazaFirst ./conf…’, y luego ‘cat trazaFirst | ./diffTime | less’)
Básicas para aprobar.
	6. En los bucles principales de su código, sólo se emplean más de 100 microsegundos en operaciones de select (no en write, read, recvfrom…) en el laboratorio (del orden de 1 ms si ejecuta el código en una máquina virtual). Puede probarlo haciendo cat trazaFirst | ./diffTime | grep read | less
	
	7. El intervalo entre operaciones de read consecutivas a la tarjeta de sonido es el esperado (según el –l utilizado). Pruebe –l20 y –l120. Puede probarlo haciendo cat trazaFirst | grep read | ./diffTime | less. (observe la diferencia de orden entre el grep y el diffTime respecto al punto anterior)
	
	8. El código no está en modo ‘espera activa’, sino que se bloquea del orden de milisegundos en el select esperando a que ocurran los eventos esperados
	
	9. Modifica el código para que el número de secuencia del paquete 50 se sustituya por el 51 (se envían paquetes con los intervalos esperados, pero la secuencia recibida en el otro extremo es 48, 49, 51, 52...). El otro extremo detecta que se perdió un paquete, y en el hueco del #50 reproduce la muestra recibida en el paquete #49
	
Avanzadas
	10. En la traza, observa que el valor del timer en el select es del orden del valor de –k. Pruebe para –k3000
	
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/conf spec_v4.1.pdf
 1 
 
Building conf, a simple audio conference 
application, v4.1 
 
 
In this practice, you should write an application called conf which allows establishing a point-to-point audio 
conference between two systems. In this implementation you are requested to use RTP over UDP, so you must 
read the corresponding specifications (RFC 3550, RFC 3551 and RFC 4961). 
One objective of this assignment is to become familiar with specifications written in a standard document 
(RTP/RTCP in this case, which is, by the way, a very easy protocol, compared to other specifications). Note 
that the standard specification contains sufficient information to guide your implementation choices; it even 
includes example code (for your convenience, we have extracted the code in a file rtp.h which is available 
on Aula Global, along with additional material.) Read the standard carefully before you start writing code. 
 
The main architecture of the application is as follows: 
 
 The application could be started in two ways: In first mode, where the process waits indefinitely 
for the other conf entity (second) to send data. In second mode, conf initiates communication 
by sending immediately an audio packet to first. 
 Once communication has been established between first and second, the execution code is the 
same for both. For now on, each system running conf reads data continuously from the soundcard 
(capturing the data recorded from the microphone) and sends these data to the remote conf system. 
Besides, the data received from a remote conf system is stored in a circular buffer. This buffer 
allows accumulating some amount of data to counteract for possible variations in the transmission 
delay. Once enough data has accumulated, it is transferred to the sound card and playout begins. 
 
 
Command line interface 
The command-line interface the program shall offer is the following: 
 
 
conf first [-pLOCAL_RTP_PORT] [-vVOL] [-c] [-kACCUMULATED_TIME] [-
mMULTICAST_ADDR] 
 
conf second addressOfFirst [-pLOCAL_RTP_PORT] [-vVOL] [-c] [-lPACKET_DURATION] 
[-kACCUMULATED_TIME] [-yPAYLOAD] 
 
 
Verbose mode, -c 
This parameter exists for both first and second. 
With –c (verbose mode), a dot (“.”) shall be printed each time a packet is sent and a “+” each time a packet is 
inserted in the circular buffer to be played. Besides (each of these cases is explained below in the 
specification), 
- every time packet loss is detected while checking the RTP sequence number, an ‘s’ (for sequence) is 
printed. If packets are played-out due to this event, an ‘x’ is printed 
- every time the select timer expires, a ‘t’ (for timer) is printed 
- every time a packet arrives after the timer (programmed for the case this packet would not arrive) 
expires, a ‘d’ (for delayed) is printed. 
Examples that may occur are the following (note that ‘.’ are not relevant here): 
- Packet 11 arrives, 12 is lost, and the timer for 12 expires before 13 arrives: ‘+.t+’. 
Each t displayed indicates a packet has been generated to substitute the packet expected but not 
received 
- Packet 11 arrives, 12 is lost, 14 arrives before expiring 12’s timer: ‘+..sx.x+’. 
s indicates there are missing packets before number 14 was received; x stands for packets 
number 12, other x for packet 13, then + indicates that 14 is appropriately played 
- Packet 11 arrives, the timer for 12 expires, then 12 arrives, 13 arrives on time: ‘+.t.d+’ (d is 
generated by 12 arriving when conf has already ‘created’ a packet with sequence 12) 
 
 2 
When the execution in verbose mode finishes, it must show the theoretical time required to playout the content, 
as well as the actual time required to perform the playout: time elapsed since the playout of the first packet to 
the playout of the last one (or a good approximation possible to that time); the comparison between the 
theoretical and actual playout times can be used to evaluate the quality of an implementation. 
 
-c can be independently activated in first or second. 
 
Local RTP port, -p 
This parameter exists for both first and second. 
The ports to use can be configured using –p, with a default value of 5004. 
Port numbers must be the same for both first and second modes. 
 
Volume, -v 
This parameter exists for both first and second. 
It allows setting the local volume for both recording and playout, which can have different values at first 
and at second. 
 
Accumulated time, -k 
This parameter exists for both first and second. 
–kACCUMULATED_TIME is used to indicate that ACCUMULATED_TIME milliseconds of data must be stored in 
the circular buffer before starting the playout. This time is internally rounded down by conf to a multiple of 
the actual playout time of a packet, so that an integer number of packets are buffered. For example, if –k90 is 
specified, and a packet has an actual duration of 16.00 ms, the accumulated data will correspond to 80 ms (5 
16-ms packets). 
100 ms is the default value for this parameter.
Note that when allocating memory, the circular buffer must be sized to store 200 milliseconds in addition to the 
buffering time specified in this command, to cope with possible delay variations caused by the network. For 
example, for –k50, the buffer will be sized to be able to store the data corresponding to 250 ms of playout 
(rounded down to the multiple of the actual playout time of a packet). 
-k may have different values for first and second. 
 
Multicast operation 
The application running as first must be able to use a multicast address to receive the data, as an alternative 
to receiving it from its unicast address. This is achieved by means of the –mMulticastAddr optional 
parameter for first mode (for example, -m226.0.0.100), and the addressOfFirst for second 
mode configured to the same multicast address. In the following example, first listens at multicast address 
226.0.0.100 (using –m), which is the same address to which second sends its data. 
 
Host1:~> ./conf first –m226.0.0.100 
 
Host2:~> ./conf second 226.0.0.100 
 
Remember, that the range of valid multicast addresses is 224.0.0.0 to 239.255.255.255 (we recommend you to 
use an address in the range 226.0.x.x). You can verify if the association is correct by executing a ping to the 
address. 
-m can only be used with first. 
If –m is not used, then second is started with the IP unicast address of first, as in the following example. 
 
Host1:~> ./conf first 
 
Host2:~> ./conf second 163.117.144.7 
 
Packet duration, -l 
This parameter is only available with second. 
The option –l allows specifying the duration in milliseconds of the play-out of the data being carried by a 
packet. By default, this value is 20 ms. 
The value of –l is just a hint, since the actual length used by first for the audio blocks will be rounded down to 
the immediately inferior power of 2 number of bytes, to comply with the fragment size restrictions imposed by 
the soundcard operation. 
 
 3 
first learns the audio block length when it receives the first audio packet from second, by processing the 
byte length of the UDP packet received (recvfrom system call). 
 
Payload, -y 
This parameter is only available with second. 
Two values are allowed: -y100 indicates L8 format, and –y11 indicates L16 format. The default value is L8. 
 
L8 refers to a linear coding of 8 bit per sample, single channel, sampling frequency of 8000 Hz; L16 to linear 
coding of 16 bit per sample, single channel at 44100 Hz. They are partially defined in RTP profiles for audio 
and video (RFC3551), sections 4.5.10, 4.5.11 y 6. 
Values of 100 and 11 are the payload type values to be carried in the corresponding RTP packet. 
 
In order to configure the format of soundcard playing and recording, by means of the SNDCTL_DSP_SETFMT 
command with the ioctl call), you should use format value 8 for L8, and format value 16 for L16. (Note that 
the format value refers to the value used to configure the soundcard). 
 
first learns the payload, and therefore the audio format to be used in the communication, when it receives 
the first audio packet from second, by reading it from the RTP header. 
 
Suggested structure for your code 
You should write a single program (named conf) composed of three sections: 
The first section is responsible of initiating the communication between the two modes, first and second. 
It consists of an if statement which performs different operations for first and for second. At the end of 
this section, 
- second has configured the soundcard according to the –y and –l values. It has created the circular 
buffer sized according to the information obtained from –y, -l and –k, recorded an audio block, 
inserted it in an RTP packet, and sent this (one) packet to first using the IP address introduced through 
the command line. Note that this first packet contains audio information. 
- first has received the first packet from second, learnt second’s address through the recvfrom 
system call, it has obtained the payload and length from the received packet, has configured the 
soundcard with this information, created its circular buffer (using its own –k value), and inserted the 
first block of audio data on it. 
When this section ends, either activated as first or second, conf knows the IP address of the remote 
node, the payload to use, the audio block length, has the soundcard configured, and the circular buffer created. 
From now on, the code is common for both first and second. 
 
The second section is responsible for accumulating the buffering data. In this section, both conf entities are 
recording and sending to the other endpoint, and receiving data from the network and storing it in the buffer, 
but are not sending data to the soundcard (there is no playout). To implement this application we recommend a 
model in which a single process takes care of different events1. Then, the application uses the select system 
call to wait for each one of the following events: 
 
 Once data is available (recorded) at the soundcard, it is immediately sent to the remote system2. No 
buffering is performed when sending to the other side. 
 Once data is received from the remote node (recvfrom system call), the audio data is copied into 
the circular buffer. 
 
The steady regime of the program is achieved at the third section, in which the select system call attends to 
the following operations: 
 Once data is available (recorded) at the soundcard, it is immediately sent to the remote system. No 
buffering is performed when sending to the other side. 
 Once data is received from the remote node (recvfrom system call), the audio data is copied into 
the circular buffer. 
 Writing data to the soundcard. We suggest you to try to write audio blocks the soundcard when there 
is any in the circular buffer. In other words, if there are audio blocks in the circular buffer, the 
 
1 A not recommended alternative is to choose an architecture comprised of several processes or threads, each in 
charge of a given task. 
2 Note that the generation of a fixed amount of audio data with at constant rate format requires constant time, 
so this activity is periodic. 
 4 
select system call must be programmed to request a write operation in the soundcard. The 
rationale for this is that we prefer the data to be in the soundcard than in the circular buffer, so that 
any short operating system timing variation will not impact in the playout quality. 
If the amount of data written exceeds the maximum available space in the soundcard memory, the 
operating system will block the writing operation, and it will awake the process later when there is 
enough space. 
 
RTP considerations. 
For UDP data sending, you must consider the recommendation made in RFC 4961, so that source and 
destination ports must be the same for all UDP packets generated for RTP. 
For timestamp encoding, take into account the recommendations of RFC3551: The timestamp of the RTP 
header of a packet is the timestamp corresponding to the first sample included in the packet, and the frequency 
used to mark the packets is the same as the one used for sampling. So if a packet contains 128 samples and the 
packet has a timestamp of 3300, the following packet must have a timestamp of 3428. 
 
To ease debugging, we recommend you to start sequence numbers and timestamp values by 0. Be careful with 
the coding of RTP headers to make them compliant to the standard: control fields must honor the byte order 
convention for sending data over a network, the network byte order or Most Significant Byte, in contrast to 
what it is used by our Intel systems, so that you should use the functions htonl, htons and their inverses 
ntohl and ntohs appropriately. Moreover, the audio data should be transported using an appropriate byte 
order (so that they can be received by architectures
with a different byte order and can be reconstructed in the 
correct way). Therefore, you should use conversion functions if data are recorded in a 16 bits format. 
Use also 0 and 1 for the SSRC of first and second, respectively. 
For the other packet header fields, use the value 0. 
 
Sequence number check 
For each RTP packet received from the remote conf system, the application is required to check for the 
appropriate sequence number. This check (and the operations described in this paragraph) is performed when 
the packet is received. 
We assume that packets can be lost in the network, but never reordered (this is a very simplified model of a real 
network, in which reordering may definitely occur). This assumption is raised to allow simplifying the code. 
With this ‘ordered delivery’ assumption, if we receive a packet with sequence number [X], and then a packet 
with sequence number [X+2], we must assume that only possible reason for this is that packet [X+1] has been 
lost (because reordering is impossible due to our initial assumption). 
In this case, the behavior specified for conf is that the data corresponding to [X] will be copied to the 
position in the circular buffer corresponding to [X+1], with the data corresponding to [X+2] (the same data) 
inserted right after. 
If packet [X+1] arrives later, it must be discarded. 
 
If verbose mode (-c) is active, this part of code is responsible for generating d (delay) and s (sequence) 
outputs. 
 
Late packets 
 
If verbose mode (-c) is active, this part of code is responsible for generating t (timer) outputs. 
 
 
 
 5 
Optional improvements 
1. Processing RTCP. 
The application sends RTCP information to the remote system in a periodic fashion (this is a simplification of 
the standard specification). The packets to be sent are SR packets, SDES with CNAME and TOOL 
information, and a BYE packet when the user decides to interrupt the transmission by pressing CTRL-C (the 
other communicating peer must stop its execution in a proper way). For an SR packet, it is not necessary to 
send the NTP information – you can set this value to 0. To fill in the CNAME field, you could use the 
operating system call gethostname. The BYE message, when generated, does not carry an indication of the 
reason why the session has been terminated. Remember that an SR and a SDES are always packed in the same 
UDP packet, and if necessary, a BYE message is appended to those two. The user information (SDES packet) 
could be hard-coded into the program or could be obtained from a configuration file (which is a more flexible 
option). 
In the receiver side, the application processes received RTCP information at any time. If a BYE packet is 
received, the application stops. When receiving the CNAME or TOOL message the first time, or each time you 
detect a change, you must show the value of this field on the screen. 
For the sake of simplicity, we are not requesting you to implement the RTCP soft-state approach: the 
participants of the audio conference are not going to deal with the fact that their communication partner has 
aborted the session by monitoring the time when they received information from the partner the last time. 
Therefore, the only way to terminate a session is to receive a BYE message or press CTRL-C. 
Take into account for your code that some of the implemented functions in the standard (files rfc3559.h and .c) 
can give hints on how to parse an SDES message. 
If verbose mode is active, and a RTCP message arrives, a “<” shall be printed, whereas a “>” shall be printed 
on departure of a RTCP packet. 
Use rtpdump to test that you RTCP code is compliant with the requirements stated above in this specification. 
Take into account the comments made before about the byte order of the data: If you do not use the appropriate 
format, rtpdump will not interpret the arriving data correctly. 
Proposed implementation order for RTCP: 
1. Implement the data transmission part (including the RTP headers) and verify if this part works 
correctly. 
2. Implement the generation and reception of RTCP packets. 
3. Start with the SDES packets, which are very easy to construct and to interpret. Test whether they are 
generated and received correctly and if they are written on the screen when required. 
4. Thereafter, incorporate the SR packets. Verify that they are sent and received and that the transmitted 
data are reasonable. 
5. Implement the BYE functionality. 
6. Test with rtpdump that the format of the sent packets is correct (even if your code understands what 
it receives, this does not mean that it conforms to the standard. It must be understood by any 
RTP/RTCP application). 
1.1. A simplified enhancement is to implement only the BYE functionality. In this case, only BYE messages 
are generated, although these messages must be in the proper format (so that rtpdump could parse the 
information exchanged). 
 
2. Support of out-of-order packets 
You can improve the practice by supporting out-of-order packets. In order to do so, we propose you that 
modify the circular buffer that we provide you in the following manner: Introduce for each memory block a 
variable that allows you to store the sequence number (transmitted by RTP) corresponding to the data block 
contained in that sequence. If N is the number or blocks that contain the circular buffer, always put the block of 
data with sequence number S in the position of the buffer ‘S module N’, and update the value of the number of 
sequence associated to that block. In that way each data block has a fixed place, and it is possible to place 
appropriately data blocks that arrive later than other that come after them in the playback logic sequence. When 
you playback a data block, check that it corresponds to the expected sequence number (on the contrary, 
playback the block coming immediately before it). 
 
3. Silence detector 
Implement a 'silence detector' heuristic and avoid sending packets identified as silent. 
When data packets are sent after a silence period, timestamps are configured to indicate the time at which this 
data burst must start. 
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/conf.h/*******************************************************/
/* conf.h */
/*******************************************************/
#ifndef SIMPLECONF_H
#define SIMPLECONF_H
#include <sys/time.h>
#include <unistd.h>
/* -------------------------------------------------------------------------------- */
/* DEFINITIONS */
enum operat {FIRST, SECOND};
enum payload {PCMU=100, L16_1=11};
#define MaxNameLength 100
#ifndef CALL
#define CALL(v,m) {if ( (v)==-1) {perror (m); printf ("Error number: %d, %s\n", errno, strerror (errno)); exit (1); }};
#endif
/* to be used by first before knowing the length of the audio data */
#define MaxLongBuffer 65536
/* read 'rtp.h', which defines structures that complement the following one */ 
#endif /* SIMPLE_H */
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/confArgs.c/*******************************************************/
/* confArgs.c */
/*******************************************************/
/* Captures arguments for 'conf' application */
/* Al alternative to this code is to base it on the Linux standard function 'getopt_long' */
#include "conf.h"
#include "confArgs.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h> 
void captureFirst (int argc, char *argv[], char * firstMulticastIP, int * port, int *vol, int * verbose, int * bufferingTime);
void captureSecond (int argc, char *argv[], char * firstIP, int * port, int *vol, int * packetDuration, int *payload, int * verbose, int * bufferingTime);
/*=====================================================================*/
void printValues (int operation, const char * firstIP, const char * firstMulticastIP, int port, int vol, int packetDuration, int verbose, int payload, int bufferingTime)
{
	if (operation == FIRST) { 
		printf ("FIRST mode.\n");
		if (firstMulticastIP[0] == '\0') {
 	 	 printf ("Unicast IP address requested for first.\n");
 	 	}
 	 	else printf ("Multicast IP address requested for first: %s\n", firstMulticastIP);
 	 	
 	 	printf ("Packet duration %d ms.\n", packetDuration);
 	}		
 	else if (operation == SECOND) {
 		printf ("SECOND mode");
 		if (payload == PCMU)
 		{
 			printf (" with 8 bits, single channel, mu law.\n");
 		}
 		else if (payload == L16_1)
 		{
 			printf (" with PCM 16 bits, singleChannel.\n");
 		}
 		printf ("Address of first node: %s.\n", firstIP);
 
 	}
 printf ("Port used %d.\n", port);
 printf ("Volume %d.\n", vol);
 printf ("Requested buffering time: %d ms.\n", bufferingTime);
 if (verbose)
 {
 printf ("Verbose mode ON.\n");
 }
 else printf ("Verbose mode OFF.\n");
 
};
/*=====================================================================*/
void printHelp (void)
{
 printf ("\nconf first [-pLOCAL_RTP_PORT] [-c] [-vVOL] [-mMULTICAST_ADDR] [-kACCUMULATED_TIME]"
"\nconf second addressOfFirst [-pLOCAL_RTP_PORT] [-c] [-vVOL] [-lPACKET_DURATION] [-kACCUMULATED_TIME] [-yPAYLOAD]\n\n(NOTE: firstName can be either a name or an IP address\n\n");
}
/* Insert default values */
/*=====================================================================*/
void defaultValues (int *operation, char * firstIP, char * firstMulticastIP, int *port, int *vol, int *packetDuration, int *verbose, int *payload, int * bufferingTime)
{
 (*operation) = FIRST; /* not very useful, but removes gcc warning about unused operation variable */
	
 firstMulticastIP[0] = '\0';
 firstIP[0] = '\0';
 *port = 5004;
 (*vol) = 90;
 (*packetDuration) = 20; /* 20 ms */
 (* payload) = PCMU;
 (* verbose) = 0; 
 (* bufferingTime) = 100; /* 100 ms */
};
/*=====================================================================*/
void captureArguments (int argc, char *argv[], int *operation, char * firstIP, char * firstMulticastIP, int *port, int *vol, int *packetDuration, int *verbose, int *payload, int *bufferingTime)
{
 if (argc==1)
 { 
 printf ("I need to know if mode is 'first' or 'second'\n\n");	 
 printHelp ();
 exit (1); /* error */
 }
 defaultValues (operation, firstIP, firstMulticastIP, port, vol, packetDuration, verbose, payload, bufferingTime);
 /* the first argument is always the role played by the host */
 if (strcmp ("first", argv[1]) == 0)
 {
 (*operation) = FIRST;
 (*payload)=0; /* set to 0 in 'first' */
 
 if (argc > 2) /* need to obtain more arguments than './conf first' */
	{
	 captureFirst (argc-1, argv, firstMulticastIP, port, vol, verbose, bufferingTime);
	}
 }
 else if (strcmp ("second", argv[1]) == 0)
 {
 (*operation) = SECOND;
 captureSecond (argc-1, argv, firstIP, port, vol, packetDuration, payload, verbose, bufferingTime);
 }
 else 
 {
 printf ("Operation could not be identified: expecting 'first' or 'second'.\n\n");
 printHelp();
 exit (1); /* error */
 }
}
/*=====================================================================*/
void captureFirst (int argc, char *argv[], char * firstMulticastIP, int * port, int *vol, int * verbose, int * bufferingTime)
{
 int index, mostSignificantAddressComponent;
 char character;
 for ( index=2; argc>1; ++index, --argc)
 {
 if ( *argv[index] == '-')
	{ 
	 character= *(++argv[index]);
	 switch (character)
	 { 
	 case 'p': /* RTP PORT for FIRST*/ 
		if ( sscanf (++argv[index],"%d", port) != 1)
		 { 
		 printf ("\n-p must be followed by a number\n");
		 exit (1); /* error */
		 }
 
	
		if ( ! (( (*port) >= 1024) && ( (*port) <= 65535) ))
		 {	 
		 printf ("\nPort number (-p) is out of the requested range, [1024..65535]\n");
		 exit (1); /* error */
		 }
		break;
	 case 'c': /* VERBOSE */
		(*verbose) = 1;
		break;
	 
	 case 'v': /* VOLume */ 
		if ( sscanf (++argv[index],"%d", vol) != 1)
		 { 
		 printf ("\n-v must be followed by a number\n");
		 exit (1); /* error */
		 }
 
	
		if ( ! (( (*vol) >= 0) && ( (*vol) <= 100) ))
		 {	 
		 printf ("\nVolume (-v) is out of the requested range, [0..100]\n");
		 exit (1); /* error */
		 }
		break;
	 case 'm': /* address of the second - can be mcast */
		if ( sscanf (++argv[index],"%s", firstMulticastIP) != 1)
		 {
		 printf ("\nSomething should follow -m\n");
		 exit (1); /* error */
		 }
				
		/* checks that this address is multicast. Multicast addresses are in the range 224.0.0.0 through 239.255.255.255 */ 
		if ( sscanf ( firstMulticastIP, "%d.", &mostSignificantAddressComponent) != 1)
		 { 
			printf ("\nThe argument following -m does not seem to be an internet address\n");
			exit (1); /* error */
		 }
		if ( (mostSignificantAddressComponent < 224) | (mostSignificantAddressComponent > 239) )
		 {
		 printf ("\nThe argument following -m is out of the multicast address range\n");
		 exit (1); /* error */
		 }	
		break;
	 case 'k': /* Time accumulated in buffers */
		if ( sscanf (++argv[index],"%d", bufferingTime) != 1)
		 { 
		 printf ("\n-k must be followed by a number\n");
		 exit (1); /* error */
		 }
		
		if ( ! ( ((*bufferingTime) >= 0) ))
		 {	 
		 printf ("\nThe buffering time (-k) must be equal or greater than 0\n");
		 exit (1); /* error */
		 }
		break;
	 default:
	 	printf ("\nI do not understand -%c\n", character); 
		printHelp ();
		exit (1); /* error */
	 }
					
	 }
	 else 
	 { /* argument not starting with '-', reject */
	 	 printf ("Every argument of second must start with '-' \n\n");
	 	 printHelp ();
	 	 exit (1); /* error */
	 }
	
	 	 
	
 
 }
 
};
/*=====================================================================*/
void captureSecond (int argc, char *argv[], char * firstAddress, int * port, int *vol, int * packetDuration, int *payload, int * verbose, int * bufferingTime)
{
 int maxNameNumber = 1;
 
 int index;
 int nameNumber = 0;
 char character;
 for ( index=2; argc>1; ++index, --argc)
 {
 
 if ( *argv[index] == '-')
	{
	 character= *(++argv[index]);
	 switch (character)
	 { 
	 case 'p': /* PORT */ 
	 if ( sscanf (++argv[index],"%d", port) != 1)
		{ 
		 printf ("\n-p must be followed by a number\n");
		 exit (1); /* error */
		}
	 
	 
	 if ( ! (( (*port) >= 1024) && ( (*port) <= 65535 )))
		{	 
		 printf ("\nPort number is out of the requested range, [1024..65535]\n");
		 exit (1); /* error */
		}
	 break;
	 case 'c': /* VERBOSE */
	 (*verbose) = 1;
	 break;
	 
	 
	 case 'v': /* VOLume */ 
		if ( sscanf (++argv[index],"%d", vol) != 1)
		 { 
		 printf ("\n-v must be followed by a number\n");
		 exit (1); /* error */
		 }
 
	
		if ( ! (( (*vol) >= 0) && ( (*vol) <= 100) ))
		 {	 
		 printf ("\nVolume (-v) is out of the requested range, [0..100]\n");
		 exit (1); /* error */
		 }
		break;
	 
	 case 'l': /* Packet duration */
	 if ( sscanf (++argv[index],"%d", packetDuration) != 1)
		{ 
		 printf ("\n-l must be followed by a number\n");
		 exit (1); /* error */
		}
	 
	 if ( ! ( ((*packetDuration) >= 0) ))
		{	 
		 printf ("\nPacket duration (-l) must be greater than 0\n");
		 exit (1); /* error */
		}
	 break;
	 
	 
	 case 'k': /* Accumulated time in buffers */
		if
( sscanf (++argv[index],"%d", bufferingTime) != 1)
		 { 
		 printf ("\n-k must be followed by a number\n");
		 exit (1); /* error */
		 }
		
		if ( ! ( ((*bufferingTime) >= 0) ))
		 {	 
		 printf ("\nThe buffering time (-k) must be equal or greater than 0\n");
		 exit (1); /* error */
		 }
		break;
 case 'y': /* Initial PAYLOAD */
	 if ( sscanf (++argv[index],"%d", payload) != 1)
		{ 
		 printf ("\n-y must be followed by a number\n");
		 exit (1); /* error */
		}
	 
	 if ( ! ( ((*payload) == PCMU) || ( (*payload) == L16_1) ))
		{	 
		 printf ("\nUnrecognized payload number. Must be either 11 or 100.\n");
		 exit (1); /* error */
		}
	 break;
	 
	 
	 
	 default:
	 printf ("\nI do not understand -%c\n", character); 
	 printHelp ();
	 exit (1); /* error */
	 
	 
	 
	 }
	}
 
 else /* THERE IS A NAME */
 {
 strcpy (firstAddress, argv[index]);
 
	 nameNumber += 1;
	 
	 if (nameNumber > maxNameNumber)
	 {
	 printf ("I expected a single non '-' argument, the IP address, and found more\n\n");
	 printHelp ();
	 exit (1); /* error */
	 }
	
 } 
 }
 
 if (nameNumber != 1)
 {
 printf ("Could not obtain an IP address\n\n");
 printHelp();
 exit (1); /* error */
 }
 
};
	
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/confArgs.h/*******************************************************/
/* confArgs.h */
/*******************************************************/
/* Captures arguments for conf application */
/* captures arguments from command line. Initial values of the variables provided are not relevant for its operation */
void captureArguments (	int argc, char *argv[], 
	int *operation, /* Returns equested mode of operation, first or second, using the values defined in conf.h: enum operat {FIRST, SECOND}; */
	char *firstIp, /* For 'second' mode only: returns the requested address of node 'first' (for 'first' mode, it returns an empty string; 'first' should no use this value). Note that this function does not check if the string provided by the user has a valid IP address format (xxx.yyy.zzz.kkk) */ 
	char *firstMulticastIP, /* For 'first' mode only: returns the requested MULTICAST address of node 'first' if -m option is used. It returns an empty string if -m is not used in 'first' mode, or if the code is started in 'second' mode. */
	int *port, /* Both modes: returns the port requested to be used in the communication */ 
	int *vol, /* Both modes: returns the volume requested (for both playing and recording). Value in range [0..100] */
	int *packetDuration, /* Both modes: returns the requested duration of the playout of an UDP packet. Measured in ms */
	int *verbose, /* Both modes: returns if the user wants to show detailed traces (value 1) or not (value 0) */
	int *payload, /* For 'second' mode only: returns the requested payload for the communication. This is the payload to include in RTP packets. Values defined in conf.h: enum payload {PCMU=100, L16_1=11}. Therefore, in command line either number 100 or number 11 are expected. (set to 0 in 'first' mode, must not be used) */
	int *bufferingTime /* Both modes: returns the buffering time requested before starting playout. Time measured in ms. */
	);
/* prints current values - can be used for debugging */
void printValues (int operation, const char * firstIp, const char * firstMulticastIP, int port, int vol, int packetDuration, int verbose, int payload, int bufferingTime );
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/diffTime.c/* 'diffTime.c'
To compile, 
gcc -Wall -o diffTime diffTime.c 
Examples of execution
strace -tt -o trace [...] 
cat trace | grep 'write(5' | ./ diffTime
	shows in the screen the time interval between sucessive writing operations to device descriptor #5
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
int main () {
	struct timeval first, second, diff;
	long int hours, minutes;
	char s_first[1000], s_second[1000];
	int result;
	
	// Read the first two lines
	// the format of the data from strace is	 	15:24:26.607645
	// pass hours:minutes... to a 'struct timeval' variable in which seconds, which may be very large (more than 60) 
	result = scanf ("%ld:%ld:%ld.%ld %[^\n]", &hours, &minutes, &(first.tv_sec), &(first.tv_usec), s_first); /* ld to scan long int values written as decimal values */
		
	if (result!= 5) {
		printf ("I expected lines starting with something like '15:24:26.607645 ...'\n"); 
		exit (1); } // it could not read the 5 expected variables 
	first.tv_sec = first.tv_sec + minutes * 60 + hours * 60*60; 
	
	result = scanf ("%ld:%ld:%ld.%ld %[^\n]", &hours, &minutes, &(second.tv_sec), &(second.tv_usec), s_second);
	
	if (result!= 5) {
		printf ("I expected lines starting with something like '15:24:26.607645 ...'\n");
		exit (1); }
	second.tv_sec = second.tv_sec + minutes * 60 + hours * 60*60;
	
	
	while (1) { // the loop stops when an EOF 
		timersub (&second, &first, &diff);
		printf ("%ld.%6ld: %s\n", diff.tv_sec, diff.tv_usec, s_first); /* ld: long integer printed as 'decimal' */
		
		// move data from second to first
		first.tv_sec = second.tv_sec; first.tv_usec = second.tv_usec;
		strcpy (s_first, s_second);
		
		// read new data for second
		 
		result = scanf ("%ld:%ld:%ld.%ld %[^\n]", &hours, &minutes, &(second.tv_sec), &(second.tv_usec), s_second);
		if (result!=5) {
			
			if (result == EOF) {
			exit (0); } // this is assumed normal termination of the code
			else {
				printf ("Unexpected format\n");
				exit (1);
				}
		}
				
		
		second.tv_sec = second.tv_sec + minutes * 60 + hours * 60*60;
	}
	
	return 1; /* everything ended fine */
}	
		
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/rtp.h/*
 * rtp.h -- RTP header file 
 */
/* Modified for use in UC3M lab */
#include "types.h" /* changed from <sys/types.h> by Akira 12/27/01 */
#include "sysdep.h"
#if 0 /* types.h has a better definition for this. by Akira 12/27/01 */
/*
 * The type definitions below are valid for 32-bit architectures and
 * may have to be adjusted for 16- or 64-bit architectures.
 */
typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef short int16;
#endif
/*
 * System endianness -- determined by autoconf.
 */
#ifdef WORDS_BIGENDIAN
#define RTP_BIG_ENDIAN 1
#else
#define RTP_LITTLE_ENDIAN 1
#endif
/*
 * Current protocol version.
 */
#define RTP_VERSION 2
#define RTP_SEQ_MOD (1<<16)
#define RTP_MAX_SDES 255 /* maximum text length for SDES */
typedef enum {
 RTCP_SR = 200,
 RTCP_RR = 201,
 RTCP_SDES = 202,
 RTCP_BYE = 203,
 RTCP_APP = 204
} rtcp_type_t;
typedef enum {
 RTCP_SDES_END = 0,
 RTCP_SDES_CNAME = 1,
 RTCP_SDES_NAME = 2,
 RTCP_SDES_EMAIL = 3,
 RTCP_SDES_PHONE = 4,
 RTCP_SDES_LOC = 5,
 RTCP_SDES_TOOL = 6,
 RTCP_SDES_NOTE = 7,
 RTCP_SDES_PRIV = 8
} rtcp_sdes_type_t;
/* ----------------------------------------------------------------------------------------------------- */
/*
 * RTP data header
 */
typedef struct {
#if RTP_BIG_ENDIAN
 unsigned int version:2; /* protocol version */
 unsigned int p:1; /* padding flag */
 unsigned int x:1; /* header extension flag */
 unsigned int cc:4; /* CSRC count */
 unsigned int m:1; /* marker bit */
 unsigned int pt:7; /* payload type */
#elif RTP_LITTLE_ENDIAN
 unsigned int cc:4; /* CSRC count */
 unsigned int x:1; /* header extension flag */
 unsigned int p:1; /* padding flag */
 unsigned
int version:2; /* protocol version */
 unsigned int pt:7; /* payload type */
 unsigned int m:1; /* marker bit */
#else
#error Define one of RTP_LITTLE_ENDIAN or RTP_BIG_ENDIAN
#endif
 unsigned int seq:16; /* sequence number */
 u_int32 ts; /* timestamp */
 u_int32 ssrc; /* synchronization source */
 /* UC3M: in the example of the RFC, here appears a csrc field. Our application setting does not require CSRCs so the best option is to remove them */
} rtp_hdr_t;
/* UC3M : next part is RTCP-specific */
/* ----------------------------------------------------------------------------------------------------- */
/*
 * RTCP common header word
 */
typedef struct {
#if RTP_BIG_ENDIAN
 unsigned int version:2; /* protocol version */
 unsigned int p:1; /* padding flag */
 unsigned int count:5; /* varies by packet type */
#elif RTP_LITTLE_ENDIAN
 unsigned int count:5; /* varies by packet type */
 unsigned int p:1; /* padding flag */
 unsigned int version:2; /* protocol version */
#else
#error Define one of RTP_LITTLE_ENDIAN or RTP_BIG_ENDIAN
#endif
 unsigned int pt:8; /* RTCP packet type */
 unsigned int length:16; /* pkt len in words, w/o this word */
} rtcp_common_t;
/*
 * Big-endian mask for version, padding bit and packet type pair
 * XXX?
 */
#define RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe)
#define RTCP_VALID_VALUE ((RTP_VERSION << 14) | RTCP_SR)
/*
 * Reception report block
 */
typedef struct {
 u_int32 ssrc; /* data source being reported */
 unsigned int fraction:8; /* fraction lost since last SR/RR */
 int lost:24; /* cumul. no. pkts lost (signed!) */
 u_int32 last_seq; /* extended last seq. no. received */
 u_int32 jitter; /* interarrival jitter */
 u_int32 lsr; /* last SR packet from this source */
 u_int32 dlsr; /* delay since last SR packet */
} rtcp_rr_t;
/*
 * SDES item
 */
typedef struct {
 u_int8 type; /* type of item (rtcp_sdes_type_t) */
 u_int8 length; /* length of item (in octets) */
 char data[1]; /* text, not null-terminated */
} rtcp_sdes_item_t;
/*
 * One RTCP packet
 */
typedef struct {
 rtcp_common_t common; /* common header */
 union {
 /* sender report (SR) */
 struct {
 u_int32 ssrc; /* sender generating this report */
 u_int32 ntp_sec; /* NTP timestamp */
 u_int32 ntp_frac;
 u_int32 rtp_ts; /* RTP timestamp */
 u_int32 psent; /* packets sent */
 u_int32 osent; /* octets sent */ 
 rtcp_rr_t rr[1]; /* variable-length list */
 			/* UC3M: this is a generic definition. Note that in a typical application this is not known in compilation time, but depends on the number of peers you have. Real applications may not be able to use static declarations -such as this- to fill this part of the information.
 			Fortunately, in our specific case we know from the very specification of the application the number of peers we are having: 1.
 			So this definition is fine for you */
 } sr;
 /* reception report (RR) */
 struct {
 u_int32 ssrc; /* receiver generating this report */
 rtcp_rr_t rr[1]; /* variable-length list */
 } rr;
 /* source description (SDES) */
 struct rtcp_sdes {
 u_int32 src; /* first SSRC/CSRC */
 rtcp_sdes_item_t item[1]; /* list of SDES items */
 			/* UC3M: this is a generic definition. This is similar to case stated for the Sender Report. 
 			You should put here the exact number of SDES items you plan to use,... IN THIS CASE YOU WANT TO USE A DIFFERENT NUMBER, SO PLEASE CHANGE THIS VALUE */
 } sdes;
 /* BYE */
 struct {
 u_int32 src[1]; /* list of sources */
 		/* UC3M: similar consideration to the previous SR and SDES case */
 		/* UC3M: we can't express trailing text in this way. If you are using the same message all the time, count the characters, and define a char text[CHAR_NUM+1] field - remember always to finish a string with '\0' */
 } bye;
 } r;
} rtcp_t;
typedef struct rtcp_sdes rtcp_sdes_t;
/*
 * Per-source state information
 */
/* UC3M: this is the structure in which you introduce the information regarding the peer sending RTCP info to you */
#define MAX_LEN_SDES_ITEM 128
typedef struct {
 u_int16 max_seq; /* highest seq. number seen */
 u_int32 cycles; /* shifted count of seq. number cycles */
 u_int32 base_seq; /* base seq number */
 u_int32 bad_seq; /* last 'bad' seq number + 1 */
 u_int32 probation; /* sequ. packets till source is valid */
 u_int32 received; /* packets received */
 u_int32 expected_prior; /* packet expected at last interval */
 u_int32 received_prior; /* packet received at last interval */
 u_int32 transit; /* relative trans time for prev pkt */
 u_int32 jitter; /* estimated jitter */
 /* ... */
 /* UC3M specific definitions */
 char CNAME[MAX_LEN_SDES_ITEM]; /* stores the last CNAME value advertised by the peer. Must be a '\0' terminated string. */
 char TOOL[MAX_LEN_SDES_ITEM]; /* stores the last TOOL value advertised by the peer. Must be a '\0' terminated string. */
} source;
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/sysdep.h#ifndef SYSDEP_H
#define SYSDEP_H
#if defined(unix) || defined(__unix) || defined (__unix__)
/* Code for Unix. Any Unix compiler should define one of the above three
 * symbols. */
#ifndef startupSocket
#define startupSocket()
#endif
#ifndef closesocket
#define closesocket close
#endif
#ifndef write_socket
#define write_socket(r, s, l) write(r, s, l)
#endif
/* end of 'if unix' */
#elif defined(WIN32) || defined(__WIN32__)
#include <winsock2.h> /* For NT socket */
#include <ws2tcpip.h> /* IP_ADD_MEMBERSHIP */
#include <windows.h>
#include <time.h> /* time_t */
#include <utilNT.h> /* For function and struct in UNIX but not in NT */
#ifndef EADDRNOTAVAIL
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#endif
#define NOLONGLONG
#define RTP_LITTLE_ENDIAN 1
#define nextstep
/* Determine if the C(++) compiler requires complete function prototype */
#ifndef __P
#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
#define __P(x) x
#else
#define __P(x) ()
#endif
#endif
#ifdef __BORLANDC__
#include <io.h>
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif /* __BORLANDC__ */
#ifdef _MSC_VER
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define open _open
#define write _write
#define close _close
#define ftime _ftime
#define timeb _timeb
#endif /* _MSC_VER */
#ifndef SIGBUS
#define SIGBUS SIGINT
#endif
#ifndef SIGHUP
#define SIGHUP SIGINT
#endif
#ifndef SIGPIPE
#define SIGPIPE SIGINT
#endif
typedef int ssize_t;
#if 0
typedef long pid_t;
typedef long gid_t;
typedef long uid_t;
typedef unsigned long u_long;
typedef unsigned int u_int;
typedef unsigned short u_short;
typedef unsigned char u_char;
#endif
typedef char * caddr_t; /* core address */
typedef long fd_mask;
#define NBBY 8 /* number of bits in a byte */
#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
#ifndef howmany
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
#endif
struct msghdr {
 caddr_t msg_name; /* optional address */
 int msg_namelen; /* size of address */
 struct iovec *msg_iov; /* scatter/gather array */
 int msg_iovlen; /* # elements in msg_iov */
 caddr_t msg_accrights; /* access rights sent/received */
 int msg_accrightslen;
};
struct passwd {
 char *pw_name;
 char *pw_passwd;
 uid_t pw_uid;
 gid_t pw_gid;
char *pw_age;
 char *pw_comment;
 char *pw_gecos;
 char *pw_dir;
 char *pw_shell;
};
#if 0
struct ip_mreq {
 struct in_addr imr_multiaddr; /* IP multicast address of group */
 struct in_addr imr_interface; /* local IP address of interface */
};
#endif
#define ITIMER_REAL 0 /* Decrements in real time */
#ifndef _TIMESPEC_T
#define _TIMESPEC_T
typedef struct timespec { /* definition per POSIX.4 */
 time_t tv_sec; /* seconds */
 long tv_nsec; /* and nanoseconds */
} timespec_t;
#endif /* _TIMESPEC_T */
struct itimerval {
 struct timeval it_interval; /* timer interval */
 struct timeval it_value; /* current value */
};
#ifndef ETIME
#define ETIME 1
#endif
#ifndef SIGKILL
#define SIGKILL SIGTERM
#endif
#define fork() 0
#define setsid() {}
#ifndef FILE_SOCKET
#define FILE_SOCKET int
#endif
#ifndef fdopen_socket
#define fdopen_socket(f, g) &f
#endif
#ifndef fclose_socket
#define fclose_socket(f) closesocket(*f)
#endif
extern int winfd_dummy; /* for WinNT see unitNT.c by Akira 12/27/01 */
extern char getc_socket(FILE_SOCKET *f);
extern ssize_t write_socket(int fildes, const void *buf, size_t nbyte);
extern int sendmsg(int s, const struct msghdr *msg, int flags);
/* end of 'ifdef WIN32' */
#else
#error "Not Unix or WIN32 -- what system is this?"
#endif
#if !defined(sun4) && !defined(hp) && !defined(nextstep) && !defined(linux)
#include <sys/select.h> /* select() */
#endif
#endif /* end of ifdef SYSDEP_H */
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para conf/types.h#ifndef __types_h
#define __types_h
#include <limits.h>
#include <sys/types.h>
#include "sysdep.h"
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
#endif
typedef unsigned char boolean;
#ifdef __STDC__
#define MAX32U 0xFFFFFFFFU
#else
#define MAX32U 0xFFFFFFFF
#endif
#define MAX32 0x8FFFFFFF
/* 32 bit machines */
#ifndef RTP_VERSION
#if ULONG_MAX == MAX32U
typedef short int16;
typedef int int32;
typedef unsigned long u_int32;
typedef unsigned short u_int16;
/* 16 bit machines */
#elif ULONG_MAX == 0xFFFF
typedef int int16;
typedef long int32;
typedef unsigned long u_int32;
typedef unsigned int u_int16; 
/* 64 bit machines */
#else
typedef short int16;
typedef int int32;
typedef unsigned int u_int32;
typedef unsigned short u_int16;
#endif
typedef char int8;
typedef unsigned char u_int8;
#endif /* RTP_VERSION */
/* Kludge if we can't get 64-bit integers. */
#ifndef NOLONGLONG
typedef long long int int64;
typedef unsigned long long u_int64;
#else
typedef long int int64;
#endif /* NOLONGLONG */
#endif
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/audioSimple.c/*
audioSimple record|play [-b(8|16)] [stereo] [-vVOLUME] [-dDURATION] [-fFREQUENCY] fileName
Examples on how the program can be started:
./audioSimple record -b16 audioFile
./audioSimple record audioFile
./audioSimple play -b8 stereo -v90 -f8000 audioFile
To compile, execute
	make
from the command line (provided that Makefile and all the .c and .h files required are in the same directory)
Operations:
- store: reads from sound card and writes to a file
- play: the opposite to 'store'
-b 8 or 16 bits per sample
VOL volume [0..100]
DUR duration in seconds; 0 or unspecified means that Ctrol-C is the only way to stop
FRE sampling frequency in Hz
default values: 8 bits, vol 30, dur 0, sampling frequency 8000, mono
*/
/* -------------------------------------------------------------------------------- */
/* INCLUDES */
#include "audioSimpleArgs.h"
#include "configureSndcard.h"
#include <stdbool.h>
/* -------------------------------------------------------------------------------- */
/* CONSTANTS */
const int BUFFER_SIZE = 4096; /* unit of data to work with: fragment to be used in the soundcard and data to read/write on each request to the soundcard */
const int MaxLongSize = 100; /* max filename size */
void record (int descSnd, int numBytesToRead, const char *fileName, int fragmentSize);
void play (int descSnd, int numBytesToWrite, const char *fileName, int fragmentSize);
/* Duplex is not used, it is just provided as an example */
void duplex (int descSnd, int numBytesToProcess, const char *fileName, int fragmentSize);
 
char *buf;
bool allocatedBuf = false;
/*=====================================================================*/
/* activated by Ctrol-C */
void signalHandler (int sigNum __attribute__ ((unused))) /* __attribute__ ((unused)) -> this indicates gcc not to show an 'unused parameter' warning about sigNum: is not used, but the function must be declared with this parameter */
{
 printf ("audioSimple was requested to finish\n");
 if (allocatedBuf == true) free (buf);
 exit (-1);
}
/*=====================================================================*/
int main(int argc, char *argv[])
{
 struct sigaction sigInfo; /* signal conf */
 struct structSndQuality datQualitySnd;
 int vol;
 int duration, numBytes;
 char nombFich[MaxLongSize];
 int operation; /* record, play */
 int descriptorSnd;
 int requestedFragmentSize;
 /* we configure the signal */
 sigInfo.sa_handler = signalHandler;
 sigInfo.sa_flags = 0; 
 CALL (sigaction (SIGINT, &sigInfo, NULL), "Error installing signal"); 
 /* obtain values from the command line - or default values otherwise */
 captureArguments (argc, argv, &operation, &datQualitySnd, &vol, &duration, nombFich);
 /* soundcard configuration */
 descriptorSnd = 0; /* this is required to request configSnd to open the device for the first time */
 /* create snd descritor and configure soundcard to given format, frequency, number of channels. We also request setting the fragment to BUFFER_SIZE size - when BUFFER_SIZE is set to a power-of-two value, the configured fragment size - returned in 'requestedFragmentSize' should be equal to BUFFER_SIZE */
 requestedFragmentSize = BUFFER_SIZE;
 configSndcard (&descriptorSnd, &datQualitySnd, &requestedFragmentSize); 
 vol = configVol (datQualitySnd.channels, descriptorSnd, vol);
 
 /* obtained values -may differ slightly - eg. frequency - from requested values */
 printValues (operation, datQualitySnd, vol, duration, nombFich);
 printFragmentSize (descriptorSnd);
 printf ("Duration of each packet exchanged with the soundcard :%f\n", (float) requestedFragmentSize / (float) ((datQualitySnd.channels) * (datQualitySnd.format /8) * (datQualitySnd.freq)));
 numBytes = duration * (datQualitySnd.channels) * (datQualitySnd.format /8) * (datQualitySnd.freq); /* note that this is the actual frequency provided by the device */
 if (operation == RECORD)
 record (descriptorSnd, numBytes, nombFich, requestedFragmentSize); /* this function - and the following fucntions - are coded in configureSndcard */
 else if (operation == PLAY)
 play (descriptorSnd, numBytes, nombFich, requestedFragmentSize);
 /* else if (operation == DUPLEX)
 duplex (descriptorSnd, numBytes, nombFich, requestedFragmentSize); */
 close (descriptorSnd);
 return 0;
};
 
 
/*=====================================================================*/
/* this funcion creates a new file fileName. It reads numBytesToRead bytes from descSnd and stores it in the file opened. The read operation is performed in 'fragmentSize' chunks. If numBytesToRead is 0, it reads forever (in this case the application calling should handle the SIGINT signal to orderly stop the operation)
If an error is found in the configuration of the soundcard, the process is stopped and an error message reported. */ 
void record (int descSnd, int numBytesToRead, const char * fileName, int fragmentSize)
{
 int file;
 int cycles = 0;
 int maxCycles = numBytesToRead / fragmentSize; /* we round down the number of bytes to record to fit with the requested fragmentSize */
 int status;
 
 /* Creates buffer to store the audio data */
 buf = malloc (fragmentSize);
if (buf == NULL) { printf("Could not reserve memory for audio data.\n"); exit (-1); /* very unusual case */ }
 allocatedBuf = true;
 
 /* opens file for writing */
 CALL (file = open (fileName, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU), "Error creating file for writing");
 /* If it would be needed to store inside the file some data to represent the audio format, this should be the place */
 
 printf("Recording in blocks of %d bytes... :\n", fragmentSize);
 
 while ( (numBytesToRead == 0) || (cycles < maxCycles)) 
 { /* until duration, or Ctrl-C */
 /* reading blocks until there are enough data */
 status = read (descSnd, buf, fragmentSize); 
 if (status != fragmentSize)
	printf ("Recorded a different number of bytes than expected (recorded %d bytes, expected %d)\n", status, fragmentSize);
 printf (".");fflush (stdout);
 
 
 status = write (file, buf, fragmentSize);
 if (status != fragmentSize)
	perror ("Written in file a different number of bytes than expected"); 
 
 cycles ++;
 }
 
 printf("Recording finished.\n");
 free (buf);
 
}
/*=====================================================================*/
/* this function opens an existing file fileName. It reads numBytesToRead bytes from file fileName, and sends it to the soundcard. The play operation is performed in 'fragmentSize' chunks. If numBytesToRead is 0, it reads forever - the application calling should handle the SIGINT signal to orderly stop the operation.
If an error is found in the configuration of the soundcard, the process is stopped and an error message reported. */
void play (int descSnd, int numBytesToWrite, const char * fileName, int fragmentSize)
{
 int file;
 int cycles = 0;
 int maxCycles = numBytesToWrite / fragmentSize; /* we round down the number of bytes to record to fit with the requested fragmentSize */
 int status;
 /* Creates buffer to store the audio data */
 buf = malloc (fragmentSize); 
 if (buf == NULL) { perror("Could not reserve memory for audio data.\n"); exit (-1); /* very unusual case */ }
 allocatedBuf = true;
 
 /* opens file in read-only mode */
 CALL (file = open (fileName, O_RDONLY), "File could not be opened");
 /* If you need to read from the file and process the audio format, this could be the place */
 
 printf("Playing in blocks of %d bytes... :\n", fragmentSize);
 
 while ( ! (((maxCycles != 0) && (cycles > maxCycles)))) 
 { 
 status = read (file, buf, fragmentSize);
 if (status != fragmentSize)
	break; /* the file finished */
 
 
 status = write (descSnd, buf, fragmentSize); 
 if (status != fragmentSize)
 	printf ("Played a different number of bytes than expected (recorded %d bytes, expected %d)\n", status, fragmentSize);
 
 cycles ++;
 }
 printf("Playing finished.\n");
 free (buf);
};
/*=====================================================================*/
/* This function is not currently used by audioSimple; it is provided as an example of how duplex can be used. */
/* this funcion creates a new file fileName. reads numBytesToProcess bytes from the soundcard, writes again to the soundcard (so simultaneous reading and writing to the soundcard occurs), and also writes the data read to a file fileName. Read and write operations are performed in 'fragmentSize' chunks. 
If an error is found in the configuration of the soundcard, the process is stopped and an error message reported. */
void duplex (int descSnd, int numBytesToProcess, const char * fileName, int fragmentSize)
{
 int file;
 int cycles = 0;
 int maxCycles = numBytesToProcess / fragmentSize; /* we round down the number of bytes to record to fit with the requested fragmentSize */
 int status;
 int ioctl_arg = 0;
 /* Creates buffer to store the audio data */
 buf = malloc (fragmentSize); 
 if (buf == NULL) { perror("Could not reserve memory for audio data.\n"); exit (-1); /* very unusual case */ }
 allocatedBuf = true;
 
 
 /* sets soundcard in duplex mode */
 CALL( ioctl(descSnd, SNDCTL_DSP_SETDUPLEX, &ioctl_arg), "Error setting duplex mode"); 
 
 /* opens file for writing */
 CALL (file = open (fileName, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU), "Error creating file for writing");
 
 printf("Playing and storing in duplex mode, with blocks of %d bytes... :\n", fragmentSize);
 
 while ( (numBytesToProcess == 0) || (cycles < maxCycles)) 
 { 
 status = read (descSnd, buf, fragmentSize); 
 if (status != fragmentSize)
 perror("Error: number of bytes recorded different than expected");
 printf (".");fflush (stdout);
 
 status = write (descSnd, buf, fragmentSize); 
 if (status != fragmentSize)
	 perror("Error: number of bytes played different than expected");
 printf (".");fflush (stdout);
 
 status = write (file, buf, fragmentSize);
 if (status != fragmentSize)
	perror ("Error: number of bytes written to the file different than expected"); 
 
 cycles ++;
 }
 
 printf("Finished duplex mode.\n");
 free (buf);
}
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/audioSimpleArgs.c/*******************************************************/
/* audioSimpleArgs.c */
/*******************************************************/
/* captures arguments from command line for audioSimple */
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h> 
#include "audioSimpleArgs.h"
/*=====================================================================*/
void printValues (int operation, struct structSndQuality sndData, int vol, int duration, char *fileName)
{
 if (operation == RECORD) { printf ("Recording ");}
 else if (operation == PLAY) { printf ("Playing ");}
 /* else if (operation == DUPLEX) {printf ("Storing and playing in duplex mode "); } */
 else if (operation == NO_OP) {printf ("None selected ");}
 else CALL (-1, "Error: operation not defined (printVaules in 'audioSimpleArgs.c')");
 printf ("File requested \'%s\'\n", fileName);
 printf ("Bits %d, number of channels %d, sampling frequency %d\n", sndData.format, sndData.channels, sndData.freq);
 printf ("Volume %d\n", vol);
 printf ("Duration %d\n", duration);
};
/*=====================================================================*/
void printHelp (void)
{
 printf ("\naudioSimple v2.0");
 printf ("\naudioSimple record|play [-b(8|16)] [stereo] [-vVOLUME] [-dDURATION] [-fFREQUENCY] fileName\n");
}
/*=====================================================================*/
void defaultValues (struct structSndQuality *sndData, int *vol, int *dur)
{
 sndData -> format = 8;
 sndData -> channels = 1;
 sndData -> freq = 8000;
 (*vol) = 30;
 (*dur) = 0;
};
static const int numOfNamesFichMax = 1;
/*=====================================================================*/
void captureArguments (int argc, char * argv[], int *operation, struct structSndQuality *sndData, int *vol, int *dur, char *fileName)
{
int index;
char car;
int numOfNames=0;
int operationDef = 0; /* 0 if no operation has been defined, 1 otherwise */
/*set default values */
defaultValues (sndData, vol, dur);
 if (argc==1)
 { 
 printf("\nNeed at least one operation to perform (play, record).\n");
 printHelp ();
 exit(1);
 }
 for ( index=1; argc>1; ++index, --argc)
 {
 if ( *argv[index] == '-')
	{ 
	 car = *(++argv[index]);
 	 switch (car)
	 { 
	 case 'b': /* BITS */ 
	 if ( sscanf (++argv[index],"%d", &(sndData->format)) != 1)
		{ 
		 printf ("\n-b must be followed by a number.\n");
		 exit(1);
		}
	 
	 if ( ! ( ((sndData -> format) != 8) || ((sndData -> format) != 16) ))
		{	 
		 printf ("\n-b must be followed by either '8' or '16'.\n");
		 exit(1);
		}
	 break;
	 
	 case 'v': /* VOLUME */
if ( sscanf (++argv[index],"%d", vol) != 1)
		{ 
		 printf ("\n-v must be followed by a number\n");
		 exit(1);
		}
	 
	 if ( ! ( ( (*vol) >= 0) && ((*vol) <= 100)) )
		{	 
		 printf ("\n-v must be followed by a number in the range [0..100]\n");
		 exit(1);
		}
	 break;
	 case 'f': /* FRECUENCY */ 
	 if ( sscanf (++argv[index],"%d", &(sndData->freq)) != 1)
		{ 
		 printf ("\n-f must be followed by a number\n");
		 exit(1);
		}
	 
	 if ( (sndData -> freq) <= 0)
		{	 
		 printf ("\nFrequency (-f) must be greater than 0\n");
		 exit(0);
		}
	 break;
	 
	 
	 
	 case 'd': /* DURATION */ 
	 if ( sscanf (++argv[index],"%d", dur) != 1)
		 { 
		 printf ("\n-d must be followed by a number\n");
		 exit(1);
		 }
	 
		if ( (*dur) < 0)
		 {	 
		 printf ("\nError introducing the duration\n");
		 exit(0);
		 }
		break;
		
	 default:
	 printf ("\nI do not understand -%c\n", car);
	 printHelp ();
	 exit(1);
	 }
	 
	}
 
 else /* There is a name */
	{
	 
	 if ( strcmp ( "stereo", argv[index]) == 0)
	 sndData->channels = 2;
	 else if (strcmp ("record", argv[index]) == 0)
	 {
	 (*operation) = RECORD;
	 operationDef = 1;
	 }
	 else if (strcmp ("play", argv[index]) == 0)
	 {
	 (*operation) = PLAY;
	 operationDef = 1;
	 }
	 else 
	 {
	 strcpy (fileName, argv[index]);
	 numOfNames += 1;
	 if (numOfNames > numOfNamesFichMax)
		{ 
		 printf ("\nToo many parameters\n");
		 printHelp ();
		 exit(1);
		}
	 }
	 
	}
 }
 if (numOfNames != 1)
 {
 printf("\nNeed a file name.\n");
 printHelp();
 exit(1);
 }
 if (operationDef == 0)
 {
 /* no operation has been selected. This is an error */
 printf("\nNeed at least one operation (play, record).\n");
 printHelp();
 exit(1);
 }
};
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/audioSimpleArgs.h/*******************************************************/
/* audioSimpleArgs.h */
/*******************************************************/
/* Expected format for audioSimple execution
audioSimple record|play|duplex [-b(8|16)] [stereo] [-vVOLUME] [-dDURATION] [-fFREQUENCY] fileName
*/
#ifndef AUDIO_H
#define AUDIO_H
/* audioSimple definitions */
/* -------------------------------------------------------------------------------- */
/* INCLUDES */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/soundcard.h> 
#include <signal.h>
#include <errno.h>
#include <string.h>
#include "configureSndcard.h" /* used to learn the 'structSndQuality' definition */
/* POSIBLE OPERATIONS */
enum operations {NO_OP, RECORD, PLAY, DUPLEX};
/* -------------------------------------------------------------------------------- */
/* FUNCTIONS */
/* from audioSArgs.c, for capturing arguments from command line */
void captureArguments (
		int arc,
		char * argv[],
		int *operation, /* values defined in audioConfig.h: NO_OP, RECORD, PLAY, DUPLEX, SERVER, CLIENT */
		struct structSndQuality *dataDsp, /* structure defined in audioConfig.h, contains format, channels and sampling frequency */
		int *vol, /* volumen in [0..100] range */
		int *dur, /* maximum recording/playing time, in seconds */
		char *fileName		
		);
void printHelp (void);
void printValues (int operation, struct structSndQuality datosDsp, int vol, int dur, char *fileName);
#endif /* AUDIO_H */
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/circularBuffer.c/*******************************************************/
/* circularBuffer.c */
/*******************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "circularBuffer.h"
#ifndef CALL
#define CALL(v,m) {if ( (v)==-1) {perror (m); printf ("Error number: %d, %s\n", errno, strerror (errno)); exit (1); }};
#endif
/* returns a pointer to the memory used to contain the circular buffer (including some memory space used for control). This function ALLOCATES the memory used by the circular buffer. numberOfZones is the number of blocks for the buffer. blockSize is the size in bytes of the buffer */
/* It is possible to manage many buffers for the same application - provided that this code is not accessed simultaneously*/
void * createCircularBuffer (int numberOfBlocks, int blockSize)
{
void * buffer;
int * pointerToInt;
/* structures to manage the the buffer: 5 integers at the beginning 
- number of blocks of the buffer
- size of each block
- index (0 to [numberOfBlocks - 1]) pointing to the first spare block
- index pointing to the first full block
- number of filled blocks */
 
 if ( (buffer= malloc (numberOfBlocks * blockSize + 5 * sizeof (int)) )== NULL) 
 {
 printf ("Error reserving memory in circularBuffer\n");
 exit (1);
 }
 /* initiallizing structure */
 pointerToInt = (int *) buffer;
 *(pointerToInt ) = numberOfBlocks;
 *(pointerToInt + 1) = blockSize;
 *(pointerToInt + 2) = 0; 
 *(pointerToInt + 3) = 0; 
 *(pointerToInt + 4) = 0; 
 return buffer;
}
/* returns a pointer to the first ("empty") available block to write on it, or NULL if there are no blocks (be sure that this case is considered in your code) */
void * pointerToInsertData (void * buffer)
{
 int * ptrNextFreeBlock, * ptrBlockNumber, * ptrBlockSize; 
 int * ptrFullBlockNmb;
 int * returnPtr;
 ptrBlockNumber = (int *) buffer;
 ptrBlockSize = (int *) (buffer + 1 * sizeof (int));
 ptrNextFreeBlock = (int *) (buffer + 2 * sizeof (int));
 /* ptrNextFullBlock is not used */
 ptrFullBlockNmb = (int *) (buffer + 4 * sizeof (int));
 returnPtr = buffer + 5 * sizeof (int) + (* ptrNextFreeBlock) * (* ptrBlockSize);
 if ( (*ptrFullBlockNmb) == (* ptrBlockNumber) )
 { /* buffer is full*/
	 return (NULL);
 }
 else
 { /* normal condition */
 (* ptrNextFreeBlock) = ((* ptrNextFreeBlock) + 1) % (* ptrBlockNumber); /* updates free block state */
 (*ptrFullBlockNmb) = (*ptrFullBlockNmb) + 1;
 return (returnPtr);
 }
};
/* returns a pointer to the first available block to be read, or NULL if there are no blocks (be sure that this case is considered in your code) */
void * pointerToReadData (void * buffer)
{
 int *ptrNextFullBlock, * ptrBlockNumber, * ptrBlockSize; 
 int *ptrFullBlockNmb;
 int * returnPtr;
 ptrBlockNumber = (int *) buffer;
 ptrBlockSize = (int *) (buffer + 1 * sizeof (int));
/* ptrNextFreeBlock is not used */
 ptrNextFullBlock = (int *) (buffer + 3 * sizeof (int));
 ptrFullBlockNmb = (int *) (buffer + 4 * sizeof (int));
 returnPtr = buffer + 5 * sizeof (int) + (* ptrNextFullBlock) * (* ptrBlockSize);
 if ( (*ptrFullBlockNmb) == 0)
 { /* circular buffer is empty */
	 return (NULL);
 }
 else
 { /* normal condition */
 (* ptrNextFullBlock) = ((*ptrNextFullBlock) + 1) % (* ptrBlockNumber); 
 (*ptrFullBlockNmb) = (*ptrFullBlockNmb) - 1;
 return (returnPtr);
 }
}
/* frees memory of the buffer. Must be executed before exiting from the process */
void destroyBuffer (void *buffer)
{
 free (buffer);
}
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/circularBuffer.h/*******************************************************/
/* circularBuffer.h */
/*******************************************************/
/* Declaration of functions for managing a circular buffer */
/* 
Only use in single-process code,
such as one managing concurrency by select. 
It allows many buffers existing at the same time.
The pointer returned by executing createCircularBuffer is the pointer that identifies a particular circular buffer, and is the one required for the rest of the calls
From now on, pointerToInsertData request an available block (for example, to write a data block received from the network).
The opposite operation, accessing to a block, is performed with pointerToReadData
Finally, destroyBuffer frees the memory allocated for the buffer. */
/* ---------------------------------------------------------*/
/* returns a pointer to the memory used to contain the circular buffer (including some memory space used for control). This function ALLOCATES the memory used by the circular buffer. numberOfZones is the number of blocks for the buffer. blockSize is the size in bytes of the buffer */
void * createCircularBuffer (int numberOfZones, int blockSize);
/* returns a pointer to the first ("empty") available block to write on it, or NULL if there are no blocks (be sure that this case is considered in your code!) */
void * pointerToInsertData (void * buffer);
/* returns a pointer to the first available block to be read, or NULL if there are no blocks (be sure that this case is considered in your code!) */
void * pointerToReadData (void * buffer);
/* frees memory of the buffer. Must be executed before exiting from the process */
void destroyBuffer (void *buffer);
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/compilaAudioSimplegcc -Wall -Wextra -o audioSimple configureSndcard.c audioSimpleArgs.c audioSimple.c
practicas SISTEMAS Multimedia avanzado/Practica 1 RTP en C/ficheros de codigo para practica 0/configureSndcard.c/*******************************************************/
/* configureSndcard.c */
/*******************************************************/
#include "configureSndcard.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/soundcard.h>
#include <string.h> /* strerror */
unsigned int floor_log2(register unsigned int x); /* function to efficiently compute the log2 floor of an integer, i.e. the integer part of the log2 of another integer. Examples: 
floor_log2(31) -> 4
floor_log2(32) -> 5
floor_log2(33) -> 5 */
/* the floor_log2 function is defined at the end of the file */
/* SOUNDCARD CONFIGURATION */
/* We separate (bits, chan number, frequency) configuration from volume configuration */
/*=====================================================================*/
void configSndcard (int *descSnd, struct structSndQuality *datosQosSnd, int *requestedFragmentSize)
 {
 	 
 unsigned int frgmArg, requestedFrgmArg; /* local variables for fragment configuration */
 
 int ioctl_arg;	
 
 if ( (*descSnd) == 0) /* the device has not been opened before */
 {
 /* opens the audio device if it was not opened before */
 CALL ((*descSnd) = open("/dev/dsp", O_RDWR), "Error opening /dev/dsp - check (*) if file /dev/dsp exists or (*) if other program is using /dev/dsp");
 
 /* CONFIGURING FRAGMENT SIZE */
 /* It sets the fragmen size only if it is opened for the first time. Remember that this operation MUST be done before additional configuration of the sound card */
 
 /* Argument to construct: 0xMMMMSSSS , being MMMM fragments (MMMM=number of fragments) of size 2^SSSS (SSSS= log2 of the size of the fragments. 
 We set the size of the fragments, and we do not request anything about the number of fragments */ 
 requestedFrgmArg = floor_log2 (*requestedFragmentSize); /* floor_log2 is defined at the end of this file. Sets ‘SSSS’ part of fragment argument */ 
 
 if (requestedFrgmArg > 16) { /* too large value, exceeds 65536 fragment size */
 	 perror ("Requested fragment size is too large, exceeds 65536\n"); 
 	 exit (-1);
 }
 requestedFrgmArg = requestedFrgmArg | 0x7fff0000 ; /* this value is used to request the soundcard not to limit the number of fragments available. Sets ‘MMMM’ part of fragment argument */
 
 frgmArg = requestedFrgmArg;
 CALL (ioctl ( (*descSnd), SNDCTL_DSP_SETFRAGMENT, &frgmArg), "Failure when setting the fragment size\n");
 if (frgmArg != requestedFrgmArg) 
 	 { printf ("Fragment size could not be set to the requested value: requested argument was %d, resulting argument is %d\n", requestedFrgmArg, frgmArg); 
 	 exit (-1);}
 
 /* returns configured fragment value, in bytes, so it performs 2^frgmArg by shifting one bit the appropriate number of times */
 *requestedFragmentSize = 1 << frgmArg; /* returns actual configured value of the fragment size, in bytes*/
 }
 /* WARNING: this must be done in THIS ORDER: bits, chan number, frequency. There are some sampling frequencies that are not supported for some bit configurations... */ 
 
 /* The soundcard format configured by SNDCTL_DSP_SETFMT indicates if there is any compression in the audio played/recorded, and the number of bits used. There are many formats defined in /usr/include/linux/soundcard.h. To illustrate this, we next copy from soundcard.h some of them: 
 
 #define SNDCTL_DSP_SETFMT _SIOWR('P',5, int) -- Selects ONE fmt
 # define AFMT_QUERY 0x00000000 -- Return current fmt 
 # define AFMT_MU_LAW 0x00000001
 # define AFMT_A_LAW 0x00000002
 # define AFMT_IMA_ADPCM 0x00000004
 # define AFMT_U8 0x00000008
 # define AFMT_S16_LE 0x00000010 -- Little endian signed 16
 # define AFMT_S16_BE 0x00000020 -- Big endian signed 16
 # define AFMT_S8 0x00000040
 # define AFMT_U16_LE 0x00000080 -- Little endian U16 
 # define AFMT_U16_BE 0x00000100 -- Big endian U16 
 # define AFMT_MPEG 0x00000200 -- MPEG (2) audio 
 # define AFMT_AC3 	 0x00000400 Dolby Digital AC3 
 For audioSimple (and in general in this lab) we are interested in uncompressed, linear quantified, formats, either 8 and 16 bits. 
 The format values reserved for this are AFMT_U8 (decimal value 8) and AFMT_S16_LE (decimal value 16).
 So selecting the appropriate format for our application is setting 8 or 16 in the format value, which is consistent with the value of 'datosQosSnd -> format'*/
 ioctl_arg = (datosQosSnd->format); 
 
 CALL( ioctl((*descSnd), SNDCTL_DSP_SETFMT, &ioctl_arg), "Error in the ioctl which sets the format/bit number"); 
 if (ioctl_arg != (datosQosSnd-> format))
 printf("It was not possible to set the requested format/bit number (you requested %d, the ioctl system call returned %d).\n", datosQosSnd->format, ioctl_arg);
 ioctl_arg = (datosQosSnd->channels); 
 CALL(ioctl((*descSnd), SNDCTL_DSP_CHANNELS, &ioctl_arg), "Error in the ioctl which sets the number of channels");
 if (ioctl_arg != (datosQosSnd->channels))
 printf("It was not possible to set the requested number of channels (you requested %d, the ioctl system call returned %d).\n", datosQosSnd->channels, ioctl_arg);
 ioctl_arg = (datosQosSnd->freq);	 
 CALL (ioctl((*descSnd), SNDCTL_DSP_SPEED, &ioctl_arg), "Error in the ioctl which sets the sampling frequency");
 if (ioctl_arg != (datosQosSnd->freq)) {
 	printf ("You requested %d Hz sampling frequency, the system call returned %d. If the difference is not much, this is not an error", datosQosSnd->freq, ioctl_arg); }
 datosQosSnd -> freq = ioctl_arg;
 
 }
/*=====================================================================*/

Continuar navegando