⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inetwvin.cpp

📁 Mobile STK for Symbian OS V0.1
💻 CPP
字号:
/***************************************************//*! \class InetWvIn    \brief STK internet streaming input class.    This Wvin subclass reads streamed audio data over a network via a    TCP or UDP socket connection.  The data is assumed in big-endian,    or network, byte order.  Only a single socket connection is    supported.    InetWvIn supports multi-channel data.  It is important to    distinguish the tick() methods, which return samples produced by    averaging across sample frames, from the tickFrame() methods,    which return references or pointers to multi-channel sample    frames.    This class implements a socket server.  When using the TCP    protocol, the server "listens" for a single remote connection    within the InetWvIn::start() function.  For the UDP protocol, no    attempt is made to verify packet delivery or order.  The default    data type for the incoming stream is signed 16-bit integers,    though any of the defined StkFormats are permissible.    by Perry R. Cook and Gary P. Scavone, 1995 - 2005.*//***************************************************/#include "InetWvIn.h"#if !defined(SYMBIAN)extern "C" THREAD_RETURN THREAD_TYPE inputThread( void * ptr ){  ThreadInfo *info = (ThreadInfo *)ptr;  while ( !info->finished ) {    ((InetWvIn *) info->object)->receive();  }  return 0;}InetWvIn :: InetWvIn( unsigned long bufferFrames, unsigned int nBuffers )  :soket_(0), buffer_(0), bufferFrames_(bufferFrames), bufferBytes_(0), nBuffers_(nBuffers), connected_(false){  threadInfo_.finished = false;  threadInfo_.object = (void *) this;  // Start the input thread.  if ( !thread_.start( &inputThread, &threadInfo_ ) ) {    errorString_ << "InetWvIn(): unable to start input thread in constructor!";    handleError( StkError::PROCESS_THREAD );  }}InetWvIn :: ~InetWvIn(){  // Close down the thread.  connected_ = false;  threadInfo_.finished = true;  if ( soket_ ) delete soket_;  if ( buffer_ ) delete [] buffer_;}void InetWvIn :: listen( int port, unsigned int nChannels,                         Stk::StkFormat format, Socket::ProtocolType protocol ){  mutex_.lock();  if ( connected_ ) delete soket_;  if ( nChannels < 1 ) {    errorString_ << "InetWvIn()::listen(): the channel argument (" << nChannels << ") must be greater than zero.";    handleError( StkError::FUNCTION_ARGUMENT );  }  if ( format == STK_SINT16 ) dataBytes_ = 2;  else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;  else if ( format == STK_FLOAT64 ) dataBytes_ = 8;  else if ( format == STK_SINT8 ) dataBytes_ = 1;  else {    errorString_ << "InetWvIn(): unknown data type specified (" << format << ").";    handleError( StkError::FUNCTION_ARGUMENT );  }   dataType_ = format;  unsigned long bufferBytes = bufferFrames_ * nBuffers_ * nChannels * dataBytes_;  if ( bufferBytes > bufferBytes_ ) {    if ( buffer_) delete [] buffer_;    buffer_ = (char *) new char[ bufferBytes ];    bufferBytes_ = bufferBytes;  }  data_.resize( bufferFrames_, nChannels );  lastOutputs_.resize( 1, nChannels, 0.0 );  bufferCounter_ = 0;  writePoint_ = 0;  readPoint_ = 0;  bytesFilled_ = 0;  if ( protocol == Socket::PROTO_TCP ) {    TcpServer *socket = new TcpServer( port );    errorString_ << "InetWvIn:listen(): waiting for TCP connection on port " << socket->port() << " ... ";    handleError( StkError::STATUS );    fd_ = socket->accept();    if ( fd_ < 0) {      errorString_ << "InetWvIn::listen(): Error accepting TCP connection request!";      handleError( StkError::PROCESS_SOCKET );    }    errorString_ << "InetWvIn::listen(): TCP socket connection made!";    handleError( StkError::STATUS );    soket_ = (Socket *) socket;  }  else {    soket_ = new UdpSocket( port );    fd_ = soket_->id();  }  connected_ = true;  mutex_.unlock();}void InetWvIn :: receive( void ){  if ( !connected_ ) {    Stk::sleep(100);    return;  }  fd_set mask;  FD_ZERO( &mask );  FD_SET( fd_, &mask );  // The select function will block until data is available for reading.  select( fd_+1, &mask, (fd_set *)0, (fd_set *)0, NULL );  if ( FD_ISSET( fd_, &mask ) ) {    mutex_.lock();    unsigned long unfilled = bufferBytes_ - bytesFilled_;    if ( unfilled > 0 ) {      // There's room in our buffer for more data.      unsigned long endPoint = writePoint_ + unfilled;      if ( endPoint > bufferBytes_ ) unfilled -= endPoint - bufferBytes_;      int i = soket_->readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );      //int i = Socket::readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );      if ( i <= 0 ) {        errorString_ << "InetWvIn::receive(): the remote InetWvIn socket has closed.";        handleError( StkError::STATUS );        connected_ = false;        mutex_.unlock();        return;      }      bytesFilled_ += i;      writePoint_ += i;      if ( writePoint_ == bufferBytes_ )        writePoint_ = 0;      mutex_.unlock();    }    else {      // Sleep 10 milliseconds AFTER unlocking mutex.      mutex_.unlock();      Stk::sleep( 10 );    }  }}int InetWvIn :: readData( void ){  // We have two potential courses of action should this method  // be called and the input buffer isn't sufficiently filled.  // One solution is to fill the data buffer with zeros and return.  // The other solution is to wait until the necessary data exists.  // I chose the latter, as it works for both streamed files  // (non-realtime data transport) and realtime playback (given  // adequate network bandwidth and speed).  // Wait until data is ready.  unsigned long bytes = data_.size() * dataBytes_;  while ( connected_ && bytesFilled_ < bytes )    Stk::sleep( 10 );  if ( !connected_ && bytesFilled_ == 0 ) return 0;  bytes = ( bytesFilled_ < bytes ) ? bytesFilled_ : bytes;  // Copy samples from buffer to data.  StkFloat gain;  long samples = bytes / dataBytes_;  mutex_.lock();  if ( dataType_ == STK_SINT16 ) {    gain = 1.0 / 32767.0;    SINT16 *buf = (SINT16 *) (buffer_+readPoint_);    for (int i=0; i<samples; i++ ) {#ifdef __LITTLE_ENDIAN__      swap16((unsigned char *) buf);#endif      data_[i] = (StkFloat) *buf++;      data_[i] *= gain;    }  }  else if ( dataType_ == STK_SINT32 ) {    gain = 1.0 / 2147483647.0;    SINT32 *buf = (SINT32 *) (buffer_+readPoint_);    for (int i=0; i<samples; i++ ) {#ifdef __LITTLE_ENDIAN__      swap32((unsigned char *) buf);#endif      data_[i] = (StkFloat) *buf++;      data_[i] *= gain;    }  }  else if ( dataType_ == STK_FLOAT32 ) {    FLOAT32 *buf = (FLOAT32 *) (buffer_+readPoint_);    for (int i=0; i<samples; i++ ) {#ifdef __LITTLE_ENDIAN__      swap32((unsigned char *) buf);#endif      data_[i] = (StkFloat) *buf++;    }  }  else if ( dataType_ == STK_FLOAT64 ) {    FLOAT64 *buf = (FLOAT64 *) (buffer_+readPoint_);    for (int i=0; i<samples; i++ ) {#ifdef __LITTLE_ENDIAN__      swap64((unsigned char *) buf);#endif      data_[i] = (StkFloat) *buf++;    }  }  else if ( dataType_ == STK_SINT8 ) {    gain = 1.0 / 127.0;    signed char *buf = (signed char *) (buffer_+readPoint_);    for (int i=0; i<samples; i++ ) {      data_[i] = (StkFloat) *buf++;      data_[i] *= gain;    }  }  readPoint_ += bytes;  if ( readPoint_ == bufferBytes_ )    readPoint_ = 0;  bytesFilled_ -= bytes;  if ( bytesFilled_ < 0 )    bytesFilled_ = 0;  mutex_.unlock();  return samples / data_.channels();}bool InetWvIn :: isConnected( void ){  if ( bytesFilled_ > 0 || bufferCounter_ > 0 )    return true;  else    return connected_;}void InetWvIn :: computeFrame( void ){  // If no connection and we've output all samples in the queue, return.  if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) return;  if ( bufferCounter_ == 0 )    bufferCounter_ = readData();  unsigned int nChannels = lastOutputs_.channels();  long temp = (bufferFrames_ - bufferCounter_) * nChannels;  for ( unsigned int i=0; i<nChannels; i++ )    lastOutputs_[i] = data_[temp++];  bufferCounter_--;  if ( bufferCounter_ < 0 )    bufferCounter_ = 0;  return;}#endif // SYMBIAN

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -