Esempio n. 1
0
/**
 * @brief Receive an AppleMIDI command.
 * Receive a datagram and decompose the message into the message structure.
 * @private @memberof MIDIDriverAppleMIDI
 * @param driver The driver.
 * @param fd The file descriptor to use for communication.
 * @param command The command.
 * @retval 0 On success.
 * @retval >0 If the packet could not be sent.
 */
static int _applemidi_recv_command( struct MIDIDriverAppleMIDI * driver, int fd, struct AppleMIDICommand * command ) {
  unsigned int ssrc;
  unsigned int msg[16];
  int len;
  
  command->size = sizeof(command->addr);
  len = recvfrom( fd, &msg[0], sizeof(msg), 0,
                  (struct sockaddr *) &(command->addr), &(command->size) );
  if( command->addr.ss_family == AF_INET ) {
    struct sockaddr_in * a = (struct sockaddr_in *) &(command->addr);
    MIDILog( DEBUG, "recv %i bytes from %s:%i on s(%i)\n", len, inet_ntoa( a->sin_addr ), ntohs( a->sin_port ), fd );
  } else {
    MIDILog( DEBUG, "recv %i bytes from <unknown addr family> on s(%i)\n", len, fd );
  }

  command->type = ntohl( msg[0] ) & 0xffff;
  
  switch( command->type ) {
      case APPLEMIDI_COMMAND_INVITATION:
      case APPLEMIDI_COMMAND_INVITATION_ACCEPTED:
      case APPLEMIDI_COMMAND_INVITATION_REJECTED:
      case APPLEMIDI_COMMAND_ENDSESSION:
        if( len < 16 ) return 1;
        command->data.session.version = ntohl( msg[1] );
        command->data.session.token   = ntohl( msg[2] );
        command->data.session.ssrc    = ntohl( msg[3] );
        len -= 16;
        if( len > 0 ) {
          if( len > sizeof( command->data.session.name ) - 1 ) {
            len = sizeof( command->data.session.name ) - 1;
          }
          memcpy( &(command->data.session.name[0]), &msg[4], len ); 
          command->data.session.name[len] = '\0';
        }
        ssrc = command->data.session.ssrc;
        break;
      case APPLEMIDI_COMMAND_SYNCHRONIZATION:
        if( len != 36 ) return 1;
        command->data.sync.ssrc        = ntohl( msg[1] );
        command->data.sync.count       = ntohl( msg[2] ) >> 24;
        command->data.sync.timestamp1  = (unsigned long long) ntohl( msg[3] ) << 32;
        command->data.sync.timestamp1 += ntohl( msg[4] );
        command->data.sync.timestamp2  = (unsigned long long) ntohl( msg[5] ) << 32;
        command->data.sync.timestamp2 += ntohl( msg[6] );
        command->data.sync.timestamp3  = (unsigned long long) ntohl( msg[7] ) << 32;
        command->data.sync.timestamp3 += ntohl( msg[8] );
        ssrc = command->data.sync.ssrc;
        break;
      case APPLEMIDI_COMMAND_RECEIVER_FEEDBACK:
        if( len != 12 ) return 1;
        command->data.feedback.ssrc   = ntohl( msg[1] );
        command->data.feedback.seqnum = ntohl( msg[2] );
        ssrc = command->data.feedback.ssrc;
        break;
      default:
        return 1;
  }
  return 0;
}
Esempio n. 2
0
/**
 * @brief Send the given AppleMIDI command.
 * Compose a message buffer and send the datagram to the given peer.
 * @private @memberof MIDIDriverAppleMIDI
 * @param driver The driver.
 * @param fd The file descriptor to use for communication.
 * @param command The command.
 * @retval 0 On success.
 * @retval >0 If the packet could not be sent.
 */
static int _applemidi_send_command( struct MIDIDriverAppleMIDI * driver, int fd, struct AppleMIDICommand * command ) {
  unsigned int ssrc;
  unsigned int msg[16];
  int len;

  msg[0] = htonl( ( APPLEMIDI_PROTOCOL_SIGNATURE << 16 ) | command->type );
  switch( command->type ) {
      case APPLEMIDI_COMMAND_INVITATION:
      case APPLEMIDI_COMMAND_INVITATION_ACCEPTED:
      case APPLEMIDI_COMMAND_INVITATION_REJECTED:
      case APPLEMIDI_COMMAND_ENDSESSION:
        ssrc   = command->data.session.ssrc;
        msg[1] = htonl( command->data.session.version );
        msg[2] = htonl( command->data.session.token );
        msg[3] = htonl( command->data.session.ssrc );
        if( command->data.session.name[0] != '\0' ) {
          len = strlen( command->data.session.name );
          memcpy( &(msg[4]), command->data.session.name, len );
          len += 16;
        } else {
          len  = 16;
        }
        break;
      case APPLEMIDI_COMMAND_SYNCHRONIZATION:
        ssrc   = command->data.sync.ssrc;
        msg[1] = htonl( command->data.sync.ssrc );
        msg[2] = htonl( command->data.sync.count << 24 );
        msg[3] = htonl( command->data.sync.timestamp1 >> 32 );
        msg[4] = htonl( command->data.sync.timestamp1 & 0xffffffff );
        msg[5] = htonl( command->data.sync.timestamp2 >> 32 );
        msg[6] = htonl( command->data.sync.timestamp2 & 0xffffffff );
        msg[7] = htonl( command->data.sync.timestamp3 >> 32 );
        msg[8] = htonl( command->data.sync.timestamp3 & 0xffffffff );
        len    = 36;
        break;
      case APPLEMIDI_COMMAND_RECEIVER_FEEDBACK:
        ssrc   = command->data.feedback.ssrc;
        msg[1] = htonl( command->data.feedback.ssrc );
        msg[2] = htonl( command->data.feedback.seqnum );
        len    = 12;
        break;
      default:
        return 1;
  }

  if( command->addr.ss_family == AF_INET ) {
    struct sockaddr_in * a = (struct sockaddr_in *) &(command->addr);
    MIDILog( DEBUG, "send %i bytes to %s:%i on s(%i)\n", len, inet_ntoa( a->sin_addr ), ntohs( a->sin_port ), fd );
  } else {
    MIDILog( DEBUG, "send %i bytes to <unknown addr family> on s(%i)\n", len, fd );
  }
  if( sendto( fd, &msg[0], len, 0,
              (struct sockaddr *) &(command->addr), command->size ) != len ) {
    return 1;
  } else {
    return 0;
  }
}
Esempio n. 3
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;
}