Beispiel #1
0
// Crude way of automatically connecting up jack ports
static void autoconnect_jack_ports( jack_client_t* client, int port_count )
{
	const char **all_ports;
	int ch=0, err = 0;
	int i;

	// Get a list of all the jack ports
	all_ports = jack_get_ports(client, NULL, NULL, JackPortIsOutput);
	if (!all_ports) {
		MAST_FATAL("autoconnect_jack_ports(): jack_get_ports() returned NULL");
	}
	
	// Step through each port name
	for (i = 0; all_ports[i]; ++i) {
		const char* local_port = jack_port_name( g_jackport[ch] );
		
		// Connect the port
		MAST_INFO("Connecting '%s' => '%s'", all_ports[i], local_port);
		err = jack_connect(client, all_ports[i], local_port);
		if (err != 0) MAST_FATAL("connect_jack_port(): failed to jack_connect() ports: %d", err);
		
		// Found enough ports ?
		if (++ch >= port_count) break;
	}
	
	free( all_ports );
}
Beispiel #2
0
/* Callback called by JACK when audio is available
   Use as little CPU time as possible, just copy accross the audio
   into the ring buffer
*/
static int process_callback(jack_nframes_t nframes, void *arg)
{
	MastSendTool* tool = (MastSendTool*)arg;
	unsigned int channels = tool->get_input_channels();
    size_t to_write = 0, written = 0;
	unsigned int c,n;
	
	// Process channel by channel
	for (c=0; c < channels; c++)
	{	
        jack_default_audio_sample_t *buf = (jack_default_audio_sample_t*)
        	jack_port_get_buffer(g_jackport[c], nframes);
 
		// Interleave the left and right channels
		for(n=0; n<nframes; n++) {
			g_interleavebuf[(n*channels)+c] = buf[n];
		}
	}

	// Now write the interleaved audio to the ring buffer
	to_write = sizeof(float) * nframes * channels;
	written = jack_ringbuffer_write(g_ringbuffer, (char*)g_interleavebuf, to_write);
	if (to_write > written) {
		// If this goes wrong, then the buffer goes out of sync and we get static
		MAST_FATAL("Failed to write to ring ruffer, try increading the ring-buffer size");
		return 1;
	}
	
	// Signal the other thread that audio is available
	pthread_cond_signal(&g_ringbuffer_cond);

	// Success
	return 0;
}
Beispiel #3
0
/*
  mast_fill_input_buffer()
  Make sure input buffer if full of audio  
*/
size_t mast_fill_input_buffer( MastAudioBuffer* buffer )
{
	int frames_wanted = buffer->get_write_space();
	size_t bytes_wanted = frames_wanted * buffer->get_channels() * sizeof( mast_sample_t );
	size_t bytes_read = 0, frames_read = 0;



	// Keep checking that there is enough audio available
	while (jack_ringbuffer_read_space(g_ringbuffer) < bytes_wanted) {
		MAST_WARNING( "Not enough audio available in ringbuffer; waiting" );
		//MAST_DEBUG("Ring buffer is %u%% full", (jack_ringbuffer_read_space(g_ringbuffer)*100) / g_ringbuffer->size);

		// Wait for some more audio to become available
		pthread_mutex_lock(&g_ringbuffer_cond_mutex);
		pthread_cond_wait(&g_ringbuffer_cond, &g_ringbuffer_cond_mutex);
		pthread_mutex_unlock(&g_ringbuffer_cond_mutex);
	}

	// Copy frames from ring buffer to temporary buffer
	bytes_read = jack_ringbuffer_read(g_ringbuffer, (char*)buffer->get_write_ptr(), bytes_wanted);
	if (bytes_read<=0) MAST_FATAL( "Failed to read from ringbuffer" );
	if (bytes_read!=bytes_wanted) MAST_WARNING("Failed to read enough audio for a full packet");
	
	// Mark the space in the buffer as used
	frames_read = bytes_read / (buffer->get_channels() * sizeof( mast_sample_t ));
	buffer->add_frames( frames_read );

	// Return the number 
	return frames_read;
}
Beispiel #4
0
// Initialise the codec
MastCodec_MPA::MastCodec_MPA( MastMimeType *type)
	: MastCodec(type)
{

	// Set default values
	this->samplerate = MPA_DEFAULT_SAMPLERATE;
	this->channels = MPA_DEFAULT_CHANNELS;


	// Initialise twolame
	this->twolame = twolame_init();
	if (this->twolame==NULL) {
		MAST_FATAL( "Failed to initialise TwoLame" );
	}

	// Configure twolame
	if (twolame_set_num_channels( this->twolame, this->channels )) {
		MAST_WARNING( "Failed to set number of input channels" );
	}
	if (twolame_set_in_samplerate( this->twolame, this->samplerate )) {
		MAST_WARNING( "Failed to set number of input samplerate" );
	}
	
	
	// Apply MIME type parameters to the codec
	this->apply_mime_type_params( type );

	
	// Get TwoLAME ready to go...
	twolame_init_params( this->twolame );

}
Beispiel #5
0
void MastTool::set_multicast_ttl( const char* ttl_str )
{
	int ttl_int = atoi( ttl_str );
	
	if (rtp_session_set_multicast_ttl( session, ttl_int )) {
		MAST_FATAL("Failed to set multicast TTL");
	}
}
Beispiel #6
0
void MastTool::set_session_dscp( const char* dscp_str )
{
	int dscp_int = this->parse_dscp( dscp_str );

	if (rtp_session_set_dscp( this->get_session(), dscp_int )) {
		MAST_FATAL("Failed to set DSCP value");
	}

}
Beispiel #7
0
void MastTool::set_session_address( const char* in_addr )
{
	char* address = strdup( in_addr );
	char* portstr = NULL;
	int port = DEFAULT_RTP_PORT;

	// Look for port in the address
	portstr = strchr(address, '/');
	if (portstr && strlen(portstr)>1) {
		*portstr = 0;
		portstr++;
		port = atoi(portstr);
	}

	
	// Make sure the port number is even
	if (port%2 == 1) port--;
	
	
	// Send of recieve address?
	if (this->session->mode == RTP_SESSION_RECVONLY) {
	
		// Set the local address/port
		if (rtp_session_set_local_addr( session, address, port )) {
			MAST_FATAL("Failed to set local address/port (%s/%d)", address, port);
		} else {
			MAST_INFO( "Local address: %s/%d", address,  port );
		}
		
	} else if (this->session->mode == RTP_SESSION_SENDONLY) {
	
		// Set the remote address/port
		if (rtp_session_set_remote_addr( session, address, port )) {
			MAST_FATAL("Failed to set remote address/port (%s/%d)", address, port);
		} else {
			MAST_INFO( "Remote address: %s/%d", address,  port );
		}
		
	} else {
		MAST_FATAL("Mode unsupported by MastTool: %d", this->session->mode);
	}
	
	free( address );
}
Beispiel #8
0
void MastSendTool::prepare()
{

    // Display some information about the chosen payload type
    MAST_INFO( "Sending SSRC: 0x%x", session->snd.ssrc );
    MAST_INFO( "Input Format: %d Hz, %s", samplerate, channels==2 ? "Stereo" : "Mono");
    mimetype->print();


    // Load the codec
    if (codec != NULL) MAST_WARNING("Codec has already been created" );
    codec = MastCodec::new_codec( mimetype );
    if (codec == NULL) MAST_FATAL("Failed to get create codec" );
    MAST_INFO( "Output Format: %d Hz, %s", codec->get_samplerate(), codec->get_channels()==2 ? "Stereo" : "Mono");

    // Work out the payload type to use
    if (strcmp("MPA", codec->get_type())==0) {
        // MPEG Audio is a special case
        this->set_payloadtype_index( RTP_MPEG_AUDIO_PT );
        payloadtype->channels = codec->get_channels();

    } else {
        // Ask oRTP for the index
        int index = ::rtp_profile_find_payload_number( profile, codec->get_type(), codec->get_samplerate(), codec->get_channels() );
        if ( index<0 ) MAST_FATAL("Failed to get payload type information from oRTP");
        this->set_payloadtype_index( index );
    }

    // Calculate the packet size
    frames_per_packet = codec->frames_per_packet( payload_size_limit );
    if (frames_per_packet<=0) MAST_FATAL( "Invalid number of samples per packet" );

    // Create audio buffers
    input_buffer = new MastAudioBuffer( frames_per_packet, samplerate, channels );
    if (input_buffer == NULL) MAST_FATAL("Failed to create audio input buffer");
    //resampled_buffer = new MastAudioBuffer( frames_per_packet, codec->get_samplerate(), codec->get_channels() );
    //if (resampled_buffer == NULL) MAST_FATAL("Failed to create resampled audio buffer");

    // Allocate memory for the packet buffer
    payload_buffer = (u_int8_t*)malloc( payload_size_limit );
    if (payload_buffer == NULL) MAST_FATAL("Failed to allocate memory for payload buffer");

}
Beispiel #9
0
// Constructors
MastTool::MastTool( const char* tool_name, RtpSessionMode mode )
{
	int log_level = ORTP_WARNING|ORTP_ERROR|ORTP_FATAL;


	// Initialise defaults
	this->session = NULL;
	this->profile = &av_profile;
	this->mimetype = new MastMimeType();
	this->payloadtype = NULL;
	this->payloadtype_index = -1;
	this->tool_name = tool_name;
	this->payload_size_limit = DEFAULT_PAYLOAD_LIMIT;


	// Initialise the oRTP library
	ortp_init();

	
	// Set the logging message level
#ifdef DEBUGGING
	MAST_DEBUG( "Compiled with debugging enabled" );
	log_level |= ORTP_DEBUG;
	log_level |= ORTP_MESSAGE;
#endif	
	ortp_set_log_level_mask(log_level);


	// Create RTP session
	session = rtp_session_new( mode );
	if (session==NULL) {
		MAST_FATAL( "Failed to create oRTP session.\n" );	
	}

	// Enabled multicast loopback
	rtp_session_set_multicast_loopback(session, TRUE);

	// Callbacks
	rtp_session_signal_connect(session,"ssrc_changed",(RtpCallback)ssrc_changed_cb, 0);
	rtp_session_signal_connect(session,"payload_type_changed",(RtpCallback)pt_changed_cb, 0);
	rtp_session_signal_connect(session,"network_error",(RtpCallback)network_error_cb, 0);


	// Set the MPEG Audio payload type to 14 in the AV profile
	rtp_profile_set_payload(profile, RTP_MPEG_AUDIO_PT, &payload_type_mpeg_audio);


	// Set RTCP parameters
	this->set_source_sdes();

}
Beispiel #10
0
void MastTool::set_payloadtype_index( int idx )
{
	// Lookup the payload type
	PayloadType* pt = rtp_profile_get_payload( profile, idx );
	if (pt==NULL) MAST_WARNING("Failed to get payload type for index %d", idx);
	this->payloadtype = pt;
	
	// Store it
	this->payloadtype_index = idx;
	MAST_INFO( "Payload type index: %d", idx );

	// Apply it to the session
	if (rtp_session_set_send_payload_type( session, idx )) {
		MAST_FATAL("Failed to set session payload type index");
	}
}
Beispiel #11
0
// Callback called by JACK when buffersize changes
static int buffersize_callback(jack_nframes_t nframes, void *arg)
{
	MastSendTool* tool = (MastSendTool*)arg;
	int channels = tool->get_input_channels();
	MAST_DEBUG("JACK buffer size is %d samples long", nframes);

	// (re-)allocate conversion buffer
	g_interleavebuf = (jack_default_audio_sample_t*)
		realloc( g_interleavebuf, nframes * sizeof(float) * channels );
	if (g_interleavebuf == NULL) {
		MAST_FATAL("Failed to (re-)allocate the convertion buffer");
	}

	// Success
	return 0;
}
Beispiel #12
0
static void parse_cmd_line(int argc, char **argv, RtpSession* session)
{
    char* local_address = NULL;
    int local_port = DEFAULT_RTP_PORT;
    int ch;


    // Parse the options/switches
    while ((ch = getopt(argc, argv, "h?")) != -1)
        switch (ch) {
        // case 'T': FIXME: timeout?
        case '?':
        case 'h':
        default:
            usage();
        }


    // Parse the ip address and port
    if (argc > optind) {
        local_address = argv[optind];
        optind++;

        // Look for port in the address
        char* portstr = strchr(local_address, '/');
        if (portstr && strlen(portstr)>1) {
            *portstr = 0;
            portstr++;
            local_port = atoi(portstr);
        }

    } else {
        MAST_ERROR("missing address/port to receive from");
        usage();
    }

    // Make sure the port number is even
    if (local_port%2 == 1) local_port--;

    // Set the remote address/port
    if (rtp_session_set_local_addr( session, local_address, local_port )) {
        MAST_FATAL("Failed to set receive address/port (%s/%u)", local_address, local_port);
    } else {
        printf( "Receive address: %s/%u\n", local_address,  local_port );
    }

}
Beispiel #13
0
int main(int argc, char **argv)
{
    MastSendTool *tool = NULL;
    SF_INFO sfinfo;


    // Create the send tool object
    tool = new MastSendTool( MAST_TOOL_NAME );
    tool->enable_scheduling();

    // Parse the command line arguments
    // and configure the session
    parse_cmd_line( argc, argv, tool );

    // Open the input file by filename
    memset( &sfinfo, 0, sizeof(sfinfo) );
    g_input_file = sf_open(g_filename, SFM_READ, &sfinfo);
    if (g_input_file == NULL) MAST_FATAL("Failed to open input file:\n%s", sf_strerror(NULL));
    tool->set_input_channels( sfinfo.channels );
    tool->set_input_samplerate( sfinfo.samplerate );

    // Display some information about the input file
    print_file_info( g_input_file, &sfinfo );

    // Setup signal handlers
    mast_setup_signals();

    // Run the main loop
    tool->run();

    // Clean up
    delete tool;


    // Close input file
    if (sf_close( g_input_file )) {
        MAST_ERROR("Failed to close input file:\n%s", sf_strerror(g_input_file));
    }


    // Success !
    return 0;
}
Beispiel #14
0
static FILE* open_output_file( char* filename )
{
	FILE* output = NULL;


	// Open the output file
	if (strcmp(filename, "-")==0) {
		fprintf(stderr, "Output file: STDOUT\n");
		output = stdout;
	} else { 
		fprintf(stderr, "Output file: %s\n", filename);
		output = fopen( filename, "wb" );
	}

	// Check pointer isn't NULL
	if (output==NULL) {
		MAST_FATAL( "failed to open output file: %s", strerror(errno) );
	}
	
	return output;
}
Beispiel #15
0
int main(int argc, char **argv)
{
	MastSendTool *tool = NULL;
	jack_client_t* client = NULL;


	// Create the send tool object
	tool = new MastSendTool( MAST_TOOL_NAME );


	// Parse the command line arguments 
	// and configure the session
	parse_cmd_line( argc, argv, tool );


	// Initialise Jack
	client = init_jack( tool );
	if (client==NULL) MAST_FATAL( "Failed to initialise JACK client" );
	
	// Get the samplerate of the JACK Router
	tool->set_input_samplerate( jack_get_sample_rate( client ) );
	
	// Setup signal handlers
	mast_setup_signals();

	// Run the main loop
	tool->run();
	
	// Clean up
	delete tool;
	

	// Shut down JACK
	deinit_jack( client );

	
	// Success !
	return 0;
}
Beispiel #16
0
int main(int argc, char **argv)
{
    MastTool* tool = NULL;
    mblk_t* packet = NULL;
    mblk_t* body = NULL;
    PayloadType* pt = NULL;
    int payload_size = 0;


    // Create an RTP session
    tool = new MastTool( MAST_TOOL_NAME, RTP_SESSION_RECVONLY );
    if (tool==NULL) return -1;

    // Parse the command line arguments
    // and configure the session
    parse_cmd_line( argc, argv, tool->get_session() );



    // Setup signal handlers
    mast_setup_signals();

    // Recieve a single packet
    packet = tool->wait_for_rtp_packet();
    if (packet == NULL) MAST_FATAL("Failed to receive a packet");
    body = packet->b_cont;
    payload_size = (body->b_wptr - body->b_rptr);


    // Display information about the packet received
    printf("\n");
    printf("RTP Header\n");
    printf("==========\n");
    printf("Payload type    : %u\n", rtp_get_payload_type( packet ) );
    printf("Payload size    : %u bytes\n", payload_size );
    printf("Sequence Number : %u\n", rtp_get_seqnumber( packet ) );
    printf("Timestamp       : %u\n", rtp_get_timestamp( packet ) );
    printf("SSRC Identifier : %x\n", rtp_get_ssrc( packet ) );
    printf("Marker Bit      : %s\n", rtp_get_markbit( packet ) ? "Set" : "Not Set");
    printf("\n");


    // Lookup the payload type
    pt = rtp_profile_get_payload( tool->get_profile(), rtp_get_payload_type( packet ) );
    if (pt == NULL) {
        MAST_WARNING( "Payload type %u isn't registered with oRTP", rtp_get_payload_type( packet ) );
    } else {
        const char* mime_major = "?";

        printf("Payload Details\n");
        printf("===============\n");

        if (pt->type==PAYLOAD_AUDIO_CONTINUOUS) mime_major = "audio";
        else if (pt->type==PAYLOAD_AUDIO_PACKETIZED) mime_major = "audio";
        else if (pt->type==PAYLOAD_VIDEO) mime_major = "video";
        printf("Mime Type       : %s/%s\n", mime_major, pt->mime_type);

        if (pt->clock_rate)			printf("Clock Rate      : %u Hz\n", pt->clock_rate);
        if (pt->channels)			printf("Channels        : %u\n", pt->channels);
        if (pt->bits_per_sample)	printf("Bits per Sample : %u\n", pt->bits_per_sample);
        if (pt->normal_bitrate) {
            printf("Normal Bitrate  : %u kbps\n", (pt->normal_bitrate/1000));
            printf("Packet duration : %u ms\n", (payload_size*1000)/(pt->normal_bitrate/8) );
        }
        if (pt->recv_fmtp)			printf("Recieve FMTP    : %s\n", pt->recv_fmtp);
        if (pt->send_fmtp)			printf("Send FMTP       : %s\n", pt->send_fmtp);
        printf("\n");


    }


    // Parse the MPEG Audio header
    if (rtp_get_payload_type( packet ) == RTP_MPEG_AUDIO_PT) {
        /* FIXME: check fragment offset header (see rfc2250) */
        unsigned char* mpa_ptr = body->b_rptr + 4;
        MPA_Header mh;

        printf("MPEG Audio Header\n");
        printf("=================\n");

        if (!mh.parse( mpa_ptr )) {
            MAST_WARNING("Failed to parse MPEG Audio header");
        } else {
            mh.debug( stdout );
        }
    }


    // Close RTP session
    delete tool;


    // Success !
    return 0;
}
Beispiel #17
0
// Initialise Jack related stuff
static jack_client_t* init_jack( MastSendTool* tool ) 
{
	const char* client_name = tool->get_tool_name();
	jack_client_t* client = NULL;
	jack_status_t status;
	size_t ringbuffer_size = 0;
	int port_count = tool->get_input_channels();
	int i = 0;


    pthread_mutex_init(&g_ringbuffer_cond_mutex, NULL);
    pthread_cond_init(&g_ringbuffer_cond, NULL);

	// Register with Jack
	if ((client = jack_client_open(client_name, g_client_opt, &status)) == 0) {
		MAST_ERROR("Failed to start jack client: 0x%x", status);
		return NULL;
	} else {
		MAST_INFO( "JACK client registered as '%s'", jack_get_client_name( client ) );
	}

	// Create our input port(s)
	if (port_count==1) {
		if (!(g_jackport[0] = jack_port_register(client, "mono", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) {
			MAST_ERROR("Cannot register mono input port");
			return NULL;
		}
	} else {
		if (!(g_jackport[0] = jack_port_register(client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) {
			MAST_ERROR("Cannot register left input port");
			return NULL;
		}
		
		if (!(g_jackport[1] = jack_port_register(client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) {
			MAST_ERROR( "Cannot register left input port");
			return NULL;
		}
	}
	
	// Create ring buffer
	ringbuffer_size = jack_get_sample_rate( client ) * g_rb_duration * port_count * sizeof(int16_t) / 1000;
	MAST_INFO("Duration of the ring buffer is %d ms (%d bytes)", g_rb_duration, (int)ringbuffer_size );
	if (!(g_ringbuffer = jack_ringbuffer_create( ringbuffer_size ))) {
		MAST_ERROR("Cannot create ringbuffer %d", i);
		return NULL;
	}

	// Register callbacks
	jack_on_shutdown(client, shutdown_callback, tool );
	jack_set_buffer_size_callback( client, buffersize_callback, tool);
	jack_set_process_callback(client, process_callback, tool);
	
	// Create conversion buffer
	buffersize_callback( jack_get_buffer_size(client), tool );

	// Activate JACK
	if (jack_activate(client)) MAST_FATAL("Cannot activate JACK client");
	
	/* Auto connect ports ? */
	if (g_do_autoconnect) autoconnect_jack_ports( client, tool->get_input_channels() );
	
	return client;
}
Beispiel #18
0
int main(int argc, char **argv)
{
	MastTool* tool = NULL;
	RtpProfile* profile = &av_profile;
	PayloadType* pt = NULL;
	FILE* output = NULL;
	mblk_t* packet = NULL;
	int ts_diff = 0;
	int ts = 0;

	
	// Create an RTP session
	tool = new MastTool( MAST_TOOL_NAME, RTP_SESSION_RECVONLY );
	tool->enable_scheduling();


	// Parse the command line arguments 
	// and configure the session
	parse_cmd_line( argc, argv, tool );
	

	
	
	// Recieve an initial packet
	packet = tool->wait_for_rtp_packet();
	if (packet == NULL) MAST_FATAL("Failed to receive an initial packet");
	
	// Lookup the payload type
	pt = rtp_profile_get_payload( profile, rtp_get_payload_type( packet ) );
	if (pt == NULL) MAST_FATAL( "Payload type %d isn't registered with oRTP", rtp_get_payload_type( packet ) );
	fprintf(stderr, "Payload type: %s\n", payload_type_get_rtpmap( pt ));
	
	// Work out the duration of the packet
	ts_diff = mast_rtp_packet_duration( packet );
	MAST_DEBUG("ts_diff = %d", ts_diff);


	// Open the output file
	output = open_output_file( g_filename );
	if (output==NULL) MAST_FATAL( "failed to open output file" );
	
	// We can free the packet now
	freemsg( packet );
	


	// Setup signal handlers
	mast_setup_signals();


	// The main loop
	while( mast_still_running() )
	{

		// Read in a packet
		packet = rtp_session_recvm_with_ts( tool->get_session(), ts );
		if (packet==NULL) {

			MAST_DEBUG( "packet is NULL" );

		} else {
			int data_len = mast_rtp_packet_size( packet );
			if (data_len==0) {
				MAST_WARNING("Failed to get size of packet's payload");
			} else {
				unsigned char* data_ptr = packet->b_cont->b_rptr;
				int bytes_written = 0;
				
				// Skip the extra header for MPA payload
				if (rtp_get_payload_type( packet ) == RTP_MPEG_AUDIO_PT) {
					data_ptr += 4;
					data_len -= 4;
				}
				
				// Update the timestamp difference
				ts_diff = mast_rtp_packet_duration( packet );
				MAST_DEBUG("ts_diff = %d", ts_diff);
				MAST_DEBUG("data_len = %d", data_len);

				// Write to disk
				bytes_written = fwrite( data_ptr, 1, data_len, output );
				if (bytes_written != data_len) {
					MAST_ERROR("Failed to write data to disk: %s", strerror(errno) );
					break;
				}
			}
		}
		
		// Increment the timestamp for the next packet
		ts += ts_diff;
	}


	// Close output file
	if (fclose( output )) {
		MAST_ERROR("Failed to close output file:\n%s", strerror(errno));
	}
	
	// Close RTP session
	delete tool;
	
	
	// Success
	return 0;
}