/** * @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, ×tamp ); 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; }
/** * @brief Respond to a given AppleMIDI command. * Use the command as response and - if neccessary - send it back to the peer. * @private @memberof MIDIDriverAppleMIDI * @param driver The driver. * @param fd The file descriptor to be used for communication. * @param command The command. * @retval 0 On success. * @retval >0 If the packet could not be sent. */ static int _applemidi_respond(struct MIDIDriverAppleMIDI *driver, struct sock *sk, struct AppleMIDICommand *command) { struct RTPPeer *peer = NULL; switch (command->type) { case APPLEMIDI_COMMAND_INVITATION: if (sk == driver->control_socket->sk) { // event = MIDIEventCreate( // MIDI_APPLEMIDI_PEER_DID_SEND_INVITATION, NULL, "%s", // &(command->data.session.name[0]) ); // MIDIDriverTriggerEvent( &(driver->base), event ); // MIDIEventRelease( event ); } if (driver->accept) { command->type = APPLEMIDI_COMMAND_INVITATION_ACCEPTED; if (sk == driver->rtp_socket->sk) { peer = RTPPeerCreate( command->data.session.ssrc, command->size, (struct sockaddr_in *)&(command->addr)); RTPSessionAddPeer(driver->rtp_session, peer); RTPPeerRelease(peer); } } else { command->type = APPLEMIDI_COMMAND_INVITATION_REJECTED; } RTPSessionGetSSRC(driver->rtp_session, &(command->data.session.ssrc)); pr_debug("processed invitation should now answer\n"); return _applemidi_send_command(driver, sk, command); case APPLEMIDI_COMMAND_INVITATION_ACCEPTED: // TODO for receive break; case APPLEMIDI_COMMAND_INVITATION_REJECTED: // TODO for receive break; case APPLEMIDI_COMMAND_ENDSESSION: RTPSessionFindPeerBySSRC(driver->rtp_session, &peer, command->data.session.ssrc); // event = MIDIEventCreate( MIDI_APPLEMIDI_PEER_DID_END_SESSION, // NULL, "%s", &(command->data.session.name[0]) ); // MIDIDriverTriggerEvent( &(driver->base), event ); // MIDIEventRelease( event ); if (peer != NULL) { RTPSessionRemovePeer(driver->rtp_session, peer); } break; case APPLEMIDI_COMMAND_SYNCHRONIZATION: return _applemidi_sync(driver, sk, command); case APPLEMIDI_COMMAND_RECEIVER_FEEDBACK: // RTPSessionFindPeerBySSRC( driver->rtp_session, &peer, // command->data.feedback.ssrc ); // RTPMIDISessionJournalTrunkate( driver->rtpmidi_session, peer, // command->data.feedback.seqnum ); break; default: return 1; } return 0; }
static int _applemidi_start_sync( struct MIDIDriverAppleMIDI * driver, int fd, socklen_t size, struct sockaddr * addr ) { if( addr != (struct sockaddr *) &(driver->command.addr) ) memcpy( &(driver->command.addr), addr, size ); driver->command.size = size; driver->command.type = APPLEMIDI_COMMAND_SYNCHRONIZATION; driver->command.data.sync.count = 3; RTPSessionGetSSRC( driver->rtp_session, &(driver->command.data.sync.ssrc) ); return _applemidi_sync( driver, fd, &(driver->command) ); }
static int _applemidi_endsession( struct MIDIDriverAppleMIDI * driver, int fd, socklen_t size, struct sockaddr * addr ) { if( addr != (struct sockaddr *) &(driver->command.addr) ) memcpy( &(driver->command.addr), addr, size ); driver->command.size = size; driver->command.type = APPLEMIDI_COMMAND_ENDSESSION; driver->command.data.session.version = 2; driver->command.data.session.token = driver->token; RTPSessionGetSSRC( driver->rtp_session, &(driver->command.data.session.ssrc) ); strncpy( &(driver->command.data.session.name[0]), driver->name, sizeof(driver->command.data.session.name) ); return _applemidi_send_command( driver, fd, &(driver->command) ); }
/** * @brief Respond to a given AppleMIDI command. * Use the command as response and - if neccessary - send it back to the peer. * @private @memberof MIDIDriverAppleMIDI * @param driver The driver. * @param fd The file descriptor to be used for communication. * @param command The command. * @retval 0 On success. * @retval >0 If the packet could not be sent. */ static int _applemidi_respond( struct MIDIDriverAppleMIDI * driver, int fd, struct AppleMIDICommand * command ) { struct RTPPeer * peer = NULL; struct MIDIEvent * event = NULL; switch( command->type ) { case APPLEMIDI_COMMAND_INVITATION: if( fd == driver->control_socket ) { event = MIDIEventCreate( MIDI_APPLEMIDI_PEER_DID_SEND_INVITATION, NULL, "%s", &(command->data.session.name[0]) ); MIDIDriverTriggerEvent( &(driver->base), event ); MIDIEventRelease( event ); } if( driver->accept ) { command->type = APPLEMIDI_COMMAND_INVITATION_ACCEPTED; if( fd == driver->rtp_socket ) { peer = RTPPeerCreate( command->data.session.ssrc, command->size, (struct sockaddr *) &(command->addr) ); RTPSessionAddPeer( driver->rtp_session, peer ); RTPPeerRelease( peer ); } } else { command->type = APPLEMIDI_COMMAND_INVITATION_REJECTED; } RTPSessionGetSSRC( driver->rtp_session, &(command->data.session.ssrc) ); return _applemidi_send_command( driver, fd, command ); case APPLEMIDI_COMMAND_INVITATION_ACCEPTED: if( command->data.session.token == driver->token ) { if( fd == driver->control_socket ) { _applemidi_rtp_addr( command->size, (struct sockaddr *) &command->addr, (struct sockaddr *) &command->addr ); return _applemidi_invite( driver, driver->rtp_socket, command->size, (struct sockaddr *) &(command->addr) ); } else { peer = RTPPeerCreate( command->data.session.ssrc, command->size, (struct sockaddr *) &(command->addr) ); RTPSessionAddPeer( driver->rtp_session, peer ); event = MIDIEventCreate( MIDI_APPLEMIDI_PEER_DID_ACCEPT_INVITATION, NULL, "%s", &(command->data.session.name[0]) ); MIDIDriverTriggerEvent( &(driver->base), event ); MIDIEventRelease( event ); RTPPeerRelease( peer ); return _applemidi_start_sync( driver, driver->rtp_socket, command->size, (struct sockaddr *) &(command->addr) ); } } break; case APPLEMIDI_COMMAND_INVITATION_REJECTED: event = MIDIEventCreate( MIDI_APPLEMIDI_PEER_DID_REJECT_INVITATION, NULL, "%s", &(command->data.session.name[0]) ); MIDIDriverTriggerEvent( &(driver->base), event ); MIDIEventRelease( event ); break; case APPLEMIDI_COMMAND_ENDSESSION: RTPSessionFindPeerBySSRC( driver->rtp_session, &peer, command->data.session.ssrc ); event = MIDIEventCreate( MIDI_APPLEMIDI_PEER_DID_END_SESSION, NULL, "%s", &(command->data.session.name[0]) ); MIDIDriverTriggerEvent( &(driver->base), event ); MIDIEventRelease( event ); if( peer != NULL ) { RTPSessionRemovePeer( driver->rtp_session, peer ); } break; case APPLEMIDI_COMMAND_SYNCHRONIZATION: return _applemidi_sync( driver, fd, command ); case APPLEMIDI_COMMAND_RECEIVER_FEEDBACK: RTPSessionFindPeerBySSRC( driver->rtp_session, &peer, command->data.feedback.ssrc ); RTPMIDISessionJournalTrunkate( driver->rtpmidi_session, peer, command->data.feedback.seqnum ); break; default: return 1; } return 0; }