示例#1
0
/**
 * @brief Start or continue a synchronization session.
 * Continue a synchronization session identified by a given command.
 * The command must contain a pointer to a valid peer.
 * @param driver The driver.
 * @param fd The file descriptor to be used for communication.
 * @param command The previous sync command.
 * @retval 0 On success.
 * @retval >0 If the synchronization failed.
 */
static int _applemidi_sync( struct MIDIDriverAppleMIDI * driver, int fd, struct AppleMIDICommand * command ) {
  unsigned long ssrc;
  MIDITimestamp timestamp, diff;
  RTPSessionGetSSRC( driver->rtp_session, &ssrc );
  MIDIClockGetNow( driver->base.clock, &timestamp );

  if( command->type != APPLEMIDI_COMMAND_SYNCHRONIZATION || 
      command->data.sync.ssrc == ssrc ||
      command->data.sync.count > 2 ) {
    command->type = APPLEMIDI_COMMAND_SYNCHRONIZATION;
    command->data.sync.ssrc       = ssrc;
    command->data.sync.count      = 0;
    command->data.sync.timestamp1 = timestamp;
    
    driver->sync = 1;
    return _applemidi_send_command( driver, fd, command );
  } else {
    RTPSessionFindPeerBySSRC( driver->rtp_session, &(driver->peer), command->data.sync.ssrc );

    /* received packet from other peer */
    if( command->data.sync.count == 2 ) {
      /* compute media delay */
      diff = ( command->data.sync.timestamp3 - command->data.sync.timestamp1 ) / 2;
      /* approximate time difference between peer and self */
      diff = command->data.sync.timestamp3 + diff - timestamp;

      /* RTPPeerSetTimestampDiff( command->peer, diff ) */
      /* finished sync */
      command->data.sync.ssrc  = ssrc;
      command->data.sync.count = 3;

      driver->sync = 0;
      return 0;
    }
    if( command->data.sync.count == 1 ) {
      /* compute media delay */
      diff = ( command->data.sync.timestamp3 - command->data.sync.timestamp1 ) / 2;
      /* approximate time difference between peer and self */
      diff = command->data.sync.timestamp2 + diff - timestamp;

      /* RTPPeerSetTimestampDiff( command->peer, diff ) */

      command->data.sync.ssrc       = ssrc;
      command->data.sync.count      = 2;
      command->data.sync.timestamp3 = timestamp;
      
      driver->sync = 0;
      return _applemidi_send_command( driver, fd, command );
    }
    if( command->data.sync.count == 0 ) {
      command->data.sync.ssrc       = ssrc;
      command->data.sync.count      = 1;
      command->data.sync.timestamp2 = timestamp;
      
      driver->sync = 2;
      return _applemidi_send_command( driver, fd, command );
    }
  }
  return 1;
}
示例#2
0
/**
 * @brief Create a MIDIDriverAppleMIDI instance.
 * Allocate space and initialize an MIDIDriverAppleMIDI instance.
 * @public @memberof MIDIDriverAppleMIDI
 * @return a pointer to the created driver structure on success.
 * @return a @c NULL pointer if the driver could not created.
 */
struct MIDIDriverAppleMIDI *MIDIDriverAppleMIDICreate(char *name,
						      unsigned short port)
{
	struct MIDIDriverAppleMIDI *driver;
	MIDITimestamp timestamp;

	driver = kmalloc(sizeof(struct MIDIDriverAppleMIDI), GFP_KERNEL);
	if (driver == NULL) {
		return NULL;
	}
	pr_debug("placed driver at %p\n", driver);

	spin_lock_init(&(driver->lock));

	pr_debug("allocated driver structure\n");
	MIDIDriverInit(&(driver->base), name, APPLEMIDI_CLOCK_RATE,
		       (void *)driver);

	driver->control_socket = NULL;
	driver->rtp_socket = NULL;
	driver->port = port;
	driver->accept = 0xff;
	driver->sync = 0;
	strncpy(&(driver->name[0]), name, sizeof(driver->name));
	driver->name[31] = 0;

	// driver->in_queue = MIDIMessageQueueCreate();
	// driver->out_queue = MIDIMessageQueueCreate();

	// driver->base.send = &_driver_send;
	// driver->base.destroy = &_driver_destroy;

	_applemidi_connect(driver);

	pr_debug("connected sockets\n");

	driver->peer = NULL;
	driver->rtp_session = RTPSessionCreate(driver->rtp_socket);
	driver->rtpmidi_session = RTPMIDISessionCreate(driver->rtp_session);

	MIDIClockGetNow(driver->base.clock, &timestamp);

	pr_debug("init timestamp with %lld\n", timestamp);

	driver->token = timestamp;

	memset(&(driver->command), 0, sizeof(driver->command));

	driver->command.peer = NULL;

	setup_timer(&driver->timer, _applemidi_idle_timeout,
		    (unsigned long)driver);

	mod_timer(&driver->timer, jiffies + msecs_to_jiffies(5000));

	return driver;
}
示例#3
0
/**
 * @brief Process outgoing MIDI messages.
 * This is called by the generic driver interface to pass messages to this driver implementation.
 * The driver may queue outgoing messages to reduce package overhead, trading of latency for throughput.
 * @public @memberof MIDIDriverAppleMIDI
 * @param driver The driver.
 * @param message The message that should be sent.
 * @retval 0 on success.
 * @retval >0 if the message could not be processed.
 */
int MIDIDriverAppleMIDISendMessage( struct MIDIDriverAppleMIDI * driver, struct MIDIMessage * message ) {
/**
 * @todo: when midi messages get timestamped by global clock, do something different:
 * - if we use the global clock (driver->clock == global_clock) do nothing
 * - otherwise: convert timestamp between clocks
 */
  MIDITimestamp timestamp;
  MIDIClockGetNow( driver->base.clock, &timestamp );
  MIDIMessageSetTimestamp( message, timestamp );
  MIDIMessageQueuePush( driver->out_queue, message );
  return MIDIDriverAppleMIDISend( driver );
}
示例#4
0
/**
 * @brief Process outgoing MIDI messages.
 * This is called by the generic driver interface to pass messages to this driver implementation.
 * The driver may queue outgoing messages to reduce package overhead, trading of latency for throughput.
 * @public @memberof MIDIDriverAppleMIDI
 * @param driver The driver.
 * @param message The message that should be sent.
 * @retval 0 on success.
 * @retval >0 if the message could not be processed.
 */
int MIDIDriverAppleMIDISendMessage( struct MIDIDriverAppleMIDI * driver, struct MIDIMessage * message ) {
/**
 * @todo: when midi messages get timestamped by global clock, do something different:
 * - if we use the global clock (driver->clock == global_clock) do nothing
 * - otherwise: convert timestamp between clocks
 */
  MIDITimestamp timestamp;
  MIDIClockGetNow( driver->base.clock, &timestamp );
  MIDIMessageSetTimestamp( message, timestamp );
  MIDIMessageQueuePush( driver->out_queue, message );
/**
 * @todo: instead of sending directly, set a minimal timeout, just long enough so that
 * multiple messages that are queued together will be sent together.
 */
  return MIDIDriverAppleMIDISend( driver );
}
示例#5
0
/**
 * @brief Create a MIDIDriverAppleMIDI instance.
 * Allocate space and initialize an MIDIDriverAppleMIDI instance.
 * @public @memberof MIDIDriverAppleMIDI
 * @return a pointer to the created driver structure on success.
 * @return a @c NULL pointer if the driver could not created.
 */
struct MIDIDriverAppleMIDI * MIDIDriverAppleMIDICreate( char * name, unsigned short port ) {
  struct MIDIDriverAppleMIDI * driver;
  MIDITimestamp timestamp;
  int ret = 0;

  driver = malloc( sizeof( struct MIDIDriverAppleMIDI ) );
  MIDIPrecondReturn( driver != NULL, ENOMEM, NULL );
  MIDIDriverInit( &(driver->base), name, APPLEMIDI_CLOCK_RATE );
 
  driver->control_socket = 0;
  driver->rtp_socket     = 0;
  driver->port           = port;
  driver->accept         = 0;
  driver->sync           = 0;
  strncpy( &(driver->name[0]), name, sizeof(driver->name) );

  driver->in_queue  = MIDIMessageQueueCreate();
  driver->out_queue = MIDIMessageQueueCreate();
  
  driver->base.send    = &_driver_send;
  driver->base.destroy = &_driver_destroy;
  
  ret = _applemidi_connect( driver );
  if (ret==-1)
    MIDILog( ERROR, "Bind failed for port: %hu\n", port);

  driver->peer = NULL;
  driver->rtp_session     = RTPSessionCreate( driver->rtp_socket );  
  driver->rtpmidi_session = RTPMIDISessionCreate( driver->rtp_session );

  MIDIClockGetNow( driver->base.clock, &timestamp );
  MIDILog( DEBUG, "initial timestamp: %lli\n", timestamp );
  driver->token = timestamp;

  memset( &(driver->command), 0, sizeof(driver->command) );
  driver->command.peer = NULL;

  _applemidi_init_runloop_source( driver );

  return driver;
}