Example #1
0
SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, const Common::Timestamp start, const Common::Timestamp end, DisposeAfterUse::Flag disposeAfterUse)
    : _parent(parent, disposeAfterUse),
      _start(convertTimeToStreamPos(start, getRate(), getChannels())),
      _pos(0, getRate() * getChannels()),
      _length(convertTimeToStreamPos(end, getRate(), getChannels()) - _start) {

	assert(_length.totalNumberOfFrames() % getChannels() == 0);
	_parent->seek(_start);
}
MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
{
    mWriteRequested = true;
    mWriteCompleted = false;
    if (doSeek) {
        // We implement the seek callback, so this works without explicit flush
        if (!FLAC__stream_decoder_seek_absolute(mDecoder, sample)) {
            ALOGE("FLACParser::readBuffer seek to sample %lld failed", (long long)sample);
            return NULL;
        }
        ALOGV("FLACParser::readBuffer seek to sample %lld succeeded", (long long)sample);
    } else {
        if (!FLAC__stream_decoder_process_single(mDecoder)) {
            ALOGE("FLACParser::readBuffer process_single failed");
            return NULL;
        }
    }
    if (!mWriteCompleted) {
        ALOGV("FLACParser::readBuffer write did not complete");
        return NULL;
    }
    // verify that block header keeps the promises made by STREAMINFO
    unsigned blocksize = mWriteHeader.blocksize;
    if (blocksize == 0 || blocksize > getMaxBlockSize()) {
        ALOGE("FLACParser::readBuffer write invalid blocksize %u", blocksize);
        return NULL;
    }
    if (mWriteHeader.sample_rate != getSampleRate() ||
        mWriteHeader.channels != getChannels() ||
        mWriteHeader.bits_per_sample != getBitsPerSample()) {
        ALOGE("FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d -> %d/%d/%d",
                getSampleRate(), getChannels(), getBitsPerSample(),
                mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample);
        return NULL;
    }
    // acquire a media buffer
    CHECK(mGroup != NULL);
    MediaBuffer *buffer;
    status_t err = mGroup->acquire_buffer(&buffer);
    if (err != OK) {
        return NULL;
    }
    size_t bufferSize = blocksize * getChannels() * sizeof(short);
    CHECK(bufferSize <= mMaxBufferSize);
    short *data = (short *) buffer->data();
    buffer->set_range(0, bufferSize);
    // copy PCM from FLAC write buffer to our media buffer, with interleaving
    (*mCopy)(data, mWriteBuffer, blocksize, getChannels());
    // fill in buffer metadata
    CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
    FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
    int64_t timeUs = (1000000LL * sampleNumber) / getSampleRate();
    buffer->meta_data()->setInt64(kKeyTime, timeUs);
    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
    return buffer;
}
Example #3
0
SubLoopingAudioStream::SubLoopingAudioStream(SeekableAudioStream *stream,
                                             uint loops,
                                             const Common::Timestamp loopStart,
                                             const Common::Timestamp loopEnd,
                                             DisposeAfterUse::Flag disposeAfterUse)
    : _parent(stream, disposeAfterUse), _loops(loops),
      _pos(0, getRate() * getChannels()),
      _loopStart(convertTimeToStreamPos(loopStart, getRate(), getChannels())),
      _loopEnd(convertTimeToStreamPos(loopEnd, getRate(), getChannels())),
      _done(false) {
	assert(loopStart < loopEnd);

	if (!_parent->rewind())
		_done = true;
}
Example #4
0
void OgreImage::blit(const WFImage& imageToBlit, unsigned int destinationChannel, int widthOffset, int heightOffset)
{
	if (imageToBlit.getChannels() > 1) {
		return;
	}

	unsigned int width = imageToBlit.getResolution();
	size_t i, j;

	size_t wfSegmentWidth = width * getChannels();
	size_t ogreImageWidth = getResolution() * getChannels();

	const unsigned char* sourcePtr = imageToBlit.getData();

	unsigned char* destStart = getData() + destinationChannel;

	unsigned char* destEnd = getData() + getSize();
	const unsigned int channels = getChannels();

	//Consider the bitmap with a coord system where (0,0) is in the upper left and dataEnd is in the lower right.
	//Since Ogre uses a different coord system than WF we need to first place the write pointer at the lower right of
	//where we want to blit. We will the work our ways upwards to the left (while advancing normally on the WF bitmap).
	//The math is thus:
	//start with the beginning of the bitmap:
	// destStart
	//then adjust it vertically using the offset
	// destStart + (channels * getResolution() * (heightOffset
	//however, we also need to adjust it more so that it's actually on on the lower line of where we want to blit
	// destStart + (channels * getResolution() * (heightOffset + (width - 1)))
	//now add with width offset
	// destStart + (channels * getResolution() * (heightOffset + (width - 1))) + (widthOffset * channels)
	//and then finally make sure that we're positioned at the lower right
	// destStart + (channels * getResolution() * (heightOffset + (width - 1))) + (widthOffset * channels) + wfSegmentWidth
	unsigned char* writePtr = destStart + (channels * getResolution() * (heightOffset + (width - 1))) + (widthOffset * channels) + wfSegmentWidth;


	for (i = 0; i < width; ++i) {
		writePtr -= wfSegmentWidth;
		for (j = 0; j < width; ++j) {
			assert(writePtr >= destStart && writePtr < destEnd);
			*(writePtr) = *(sourcePtr + j);
			//advance the number of channels
			writePtr += channels;
		}
		writePtr -= ogreImageWidth;
		sourcePtr += imageToBlit.getResolution();
	}
}
Example #5
0
void poImage::setPixel(poPoint p, poColor c) {
	if(p.x < 0 || p.y < 0 || p.x >= getWidth() || p.y >=getHeight())
		return;
	
	uint x = p.x;
	uint y = p.y;
	
	BYTE *bits = FreeImage_GetScanLine(bitmap, y);
	switch(getChannels()) {
		case 1:
			bits[x] = (((0.21*c.R) + (0.71*c.G) + (0.07*c.B)) * c.A) * 255;
			break;
		case 2:
			bits[x*2] = ((0.21*c.R) + (0.71*c.G) + (0.07*c.B)) * 255;
			bits[x*2+1] = c.A * 255;
			break;
		case 3:
			bits[x*3] = c.R * c.A * 255;
			bits[x*3+1] = c.G * c.A * 255;
			bits[x*3+2] = c.B * c.A * 255;
			break;
		case 4:
			bits[x*4] = c.R * 255;
			bits[x*4+1] = c.G * 255;
			bits[x*4+2] = c.B * 255;
			bits[x*4+3] = c.A * 255;
			break;
	}
}
Example #6
0
poColor poImage::getPixel(poPoint p) const {
        
	if(!isValid() || p.x < 0 || p.y < 0 || p.x >= getWidth() || p.y >=getHeight())
		return poColor();

	uint x = p.x;
	uint y = p.y;
	
	BYTE* bits = FreeImage_GetScanLine(bitmap, y);
	poColor ret;
	
	switch(getChannels()) {
		case 1:
			ret.set255(bits[x], bits[x], bits[x], 255);
			break;
		case 2:
			ret.set255(bits[x*2], bits[x*2], bits[x*2], bits[x*2+1]);
			break;
		case 3:
			ret.set255(bits[x*3+0], bits[x*3+1], bits[x*3+2], 255);
			break;
		case 4:
			ret.set255(bits[x*4+0], bits[x*4+1], bits[x*4+2], bits[x*4+3]);
			break;
		default:
			;
	}
	
	return ret;
}
Example #7
0
/**
* Clones a current Image.
* If, for any reason the Image cannot be copied,
* then NULL is returned.
*/
JPGImage* JPGImage::clone(){

      //Create a new instance of JPG Image and copy
      //the features of the current instance to the new instance.
      JPGImage *j = new JPGImage();

      j->setWidth(getWidth());
      j->setHeight(getHeight());
      j->setSize(getSize());
      j->setFilename(getFilename());

      try{
          j->createPixelMatrix(j->getWidth(), j->getHeight());
      } catch (...) {
          return NULL;
      }

      for(int x = 0; x < j->getWidth(); x++){
              for (int y = 0; y < j->getHeight(); y++){
                  Pixel *p = new Pixel(getPixel(x, y));
                  j->setPixel(x, y, p);
                  delete(p);
              }
      }

      j->setImageID(getImageID());
      j->setChannels(getChannels());

          j->setGrayScaleAvaliable(isGrayScaleAvaliable());
          j->setBlackAndWhiteAvaliable(isBlackAndWhiteAvaliable());
      j->setBitsPerPixel(getBitsPerPixel());

      return j;
}
void TerminalPrinter::print(unsigned long pos){
	if(NumInputs() == 0){
		std::cout << "invalid or no Input" << std::endl;
		return;
	}
	auto tmpInfo = getInfoFromSlot(0);
	if(!tmpInfo){
		std::cout << "failed retrieving info" << std::endl;
		return;
	}
	for(unsigned int i = 0; i < tmpInfo->getChannels(); i++){
		auto tmpBuf = getFromSlot(0, pos, 1);
		if(!tmpBuf){
			std::cout << "failed retrieving buffer" << std::endl;
			return;
		}
		auto tmpSmp = getSampleFromBuffer(0, tmpBuf);
		if(!tmpSmp){
			std::cout << "failed retrieving sample" << std::endl;
			return;
		}
		std::cout << tmpSmp->get(i) << " ";
	}
	std::cout << std::endl;
	return;
}
Example #9
0
//再接続します。
void CIRCService::reconnect(void)
{
    if (m_state ==CChatServiceBase::DISCONNECT){
        // 通信を初期化
        CIRCConnection *newConnection = new CIRCConnection;

        newConnection->init(m_id, m_handler);
        newConnection->setHost(m_connect->getHost());
        newConnection->setPort(m_connect->getPort());
        // 前回接続済みのユーザーがサーバー側で切断の完了になってない場合があるので、ユーザー名を変更。
        m_user->setUserName(m_user->getUserName() + "_");

        vector<wxString> channelNames;
        vector<CChannelStatus*> channels = getChannels();
        vector<CChannelStatus*>::iterator it = channels.begin();
        while (it != channels.end()){
            channelNames.push_back((*it)->getChannelName());
            it++;
        }
        this->setSavedChannels(channelNames);
        delete m_connect;
        m_connect = newConnection;
        registerUser(m_user->getUserName(), m_user->getBasic());
        connect();
    }
}
Example #10
0
Window::~Window()
{
    LBASSERT( getChannels().empty( ));

    delete _objectManager;
    _objectManager = 0;
}
Example #11
0
/*
* Add a new PWM instance to this motor controller.
* channel - the controller channel from 1 to 10
* pin_number - the index in the PWM array defined in 'setMotors', this is the next blank slot available
* dir_pin - the direction pin for this channel
* dir_default - the default direction the motor starts in
* timer_pre - timer prescale default 1 = no prescale
* timer_res - timer resolution in bits - default 8
*/ 
void HBridgeDriver::createPWM(uint8_t channel, uint8_t pin_number, uint8_t dir_pin, uint8_t dir_default, int timer_pre, int timer_res) {
	// Attempt to assign PWM pin, lock to 8 bits no prescale, mode 2 CTC
	if( getChannels() < channel ) setChannels(channel);
	if( assignPin(pin_number) ) {
		// Set up the digital direction pin
		if( assignPin(dir_pin) ) {
			Digital* dpin = new Digital(dir_pin);
			dpin->pinMode(OUTPUT);
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = dpin;
					break;
				}
			}
			int pindex;
			for(pindex = 0; pindex < 10; pindex++) {
				if( !ppwms[pindex] )
					break;
			}
			if( ppwms[pindex] )
				return;
			currentDirection[channel-1] = dir_default;
			defaultDirection[channel-1] = dir_default;
			
			motorDrive[channel-1][0] = pindex;
			motorDrive[channel-1][1] = dir_pin;
			motorDrive[channel-1][2] = timer_pre;
			motorDrive[channel-1][3] = timer_res;
			PWM* ppin = new PWM(pin_number);
			ppwms[pindex] = ppin;
			ppwms[pindex]->init(pin_number);
		}
	}
}
AFM_API_EXPORT OMX_ERRORTYPE AFM_Encoder::getParameter(
    OMX_INDEXTYPE nParamIndex,
    OMX_PTR pComponentParameterStructure) const
{
    OMX_ERRORTYPE error = OMX_ErrorNone;

    switch (nParamIndex) {
    case AFM_IndexParamPcmLayout:
    {
        AFM_PARAM_PCMLAYOUTTYPE *pcmlayoutIn
            = (AFM_PARAM_PCMLAYOUTTYPE *) pComponentParameterStructure;


        if (pcmlayoutIn->nPortIndex != 0) {
            return OMX_ErrorBadPortIndex;
        }


        pcmlayoutIn->nBlockSize      = getSampleFrameSize();
        pcmlayoutIn->nChannels       = getChannels();
        pcmlayoutIn->nMaxChannels    = getMaxChannels();
        pcmlayoutIn->nBitsPerSample  = getSampleBitSize();
        pcmlayoutIn->nNbBuffers      = 1;

        return error;
    }

    default:
        return AFM_Component::getParameter(
                   nParamIndex, pComponentParameterStructure);
    }
}
void FLACParser::allocateBuffers()
{
    CHECK(mGroup == NULL);
    mGroup = new MediaBufferGroup;
    mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
    mGroup->add_buffer(new MediaBuffer(mMaxBufferSize));
}
	void ObjectFinder::update(cv::Mat img) {
        cv::Mat gray;
        if(getChannels(img) == 1) gray = img;
        else                      copyGray(img,gray);
        resize(gray, graySmall, rescale, rescale);
		cv::Mat graySmallMat = toCv(graySmall);
		if(useHistogramEqualization) {
			equalizeHist(graySmallMat, graySmallMat);
		}
		cv::Size minSize, maxSize;
		float averageSide = (graySmallMat.rows + graySmallMat.cols) / 2;
		if(minSizeScale > 0) {
			int side = minSizeScale * averageSide;
			minSize = cv::Size(side, side);
		}
		if(maxSizeScale < 1) {
			int side = maxSizeScale * averageSide;
			maxSize = cv::Size(side, side);
		}
		classifier.detectMultiScale(graySmallMat, objects, multiScaleFactor, minNeighbors,
																(cannyPruning ? CASCADE_DO_CANNY_PRUNING : 0) |
																(findBiggestObject ? CASCADE_FIND_BIGGEST_OBJECT | CASCADE_DO_ROUGH_SEARCH : 0),
																minSize,
																maxSize);
		for(int i = 0; i < objects.size(); i++) {
			cv::Rect& rect = objects[i];
			rect.width /= rescale, rect.height /= rescale;
			rect.x /= rescale, rect.y /= rescale;
		}
		tracker.track(objects);
	}
Example #15
0
//Format as XML tag for dvdauthor
std::string AudioStream::toXml(void) 
{
     std::ostringstream xml;
     xml << "<audio format=\"" << getFormat() << "\" channels=\"" << getChannels() << "\" ";
     xml << "quant=\"" << getQuantization() << "\" samplerate=\"" << getFrequency() << "\" lang=\"" << getLangCode() << "\"/>";    
     return xml.str();
}
Example #16
0
void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
	assert(!_finished);
	if ((stream->getRate() != getRate()) || (stream->getChannels() != getChannels()))
		error("QueuingAudioStreamImpl::queueAudioStream: stream has mismatched parameters");

	Common::StackLock lock(_mutex);
	_queue.push(StreamHolder(stream, disposeAfterUse));
}
Example #17
0
void AudioEngine::addBuffers(float *pDest, AudioBufferPtr pSrc)
{
    int numFrames = pSrc->getNumFrames();
    short * pData = pSrc->getData();
    for(int i = 0; i < numFrames*getChannels(); ++i) {
        pDest[i] += pData[i]/32768.0f;
    }
}
Example #18
0
void Widget::loadImage(const QString &fileName, QImage *image, QToolButton *button)
{
    image->load(fileName);
    *image = image->convertToFormat(QImage::Format_RGB32);
    button->setIconSize(QSize(image->width(), image->height()));
    button->setIcon(QPixmap::fromImage(*image));
    getChannels();
}
Example #19
0
void OgreImage::blit(const WFImage& imageToBlit, unsigned int destinationChannel, int widthOffset, int heightOffset)
{
	if (imageToBlit.getChannels() > 1) {
		return;
	}

	//	if (imageToBlit.getResolution() == getResolution() && widthOffset == 0 && heightOffset == 0) {
	//		const unsigned char* sourcePtr = imageToBlit.getData();
	//		unsigned char* destPtr = getData() + destinationChannel;
	//
	//		for (unsigned int i = 0; i < imageToBlit.getSize(); ++i) {
	//			*destPtr = *sourcePtr;
	//			destPtr += mChannels;
	//			sourcePtr++;
	//		}
	//	} else {
	//	unsigned int width = imageToBlit.getSize();
	unsigned int width = 64;
	size_t i, j;

	size_t wfSegmentWidth = width * getChannels();
	size_t ogreImageWidth = getResolution() * getChannels();

	const unsigned char* sourcePtr = imageToBlit.getData();
	unsigned char* destPtr = getData() + destinationChannel;

	unsigned char* dataEnd = getData() + getSize();

	unsigned char* end = destPtr + (getChannels() * getResolution() * ((width - 1) + heightOffset)) + (((width - 1) + widthOffset) * getChannels());

	unsigned char* tempPtr = end;
	for (i = 0; i < width; ++i) {
		tempPtr -= wfSegmentWidth;
		for (j = 0; j < width; ++j) {
			if (tempPtr >= getData() && tempPtr < dataEnd) {
				*(tempPtr) = *(sourcePtr + j);
			}
			//advance the number of channels
			tempPtr += getChannels();
		}
		tempPtr -= ogreImageWidth;
		sourcePtr += imageToBlit.getResolution();
	}
	//	}
}
Example #20
0
void BufferNode::bufferChanged() {
	auto buff = getProperty(Lav_BUFFER_BUFFER).getBufferValue();
	double maxPosition = 0.0;
	int newChannels= 0;
	if(buff==nullptr) {
		resize(0, 1);
		getOutputConnection(0)->reconfigure(0, 1);
	}
	else {
		newChannels = buff->getChannels() > 0 ? buff->getChannels() : 1;
		resize(0, newChannels);
		getOutputConnection(0)->reconfigure(0, newChannels);
		maxPosition =buff->getDuration();
	}
	player.setBuffer(buff);
	getProperty(Lav_BUFFER_POSITION).setDoubleValue(0.0); //the callback handles changing everything else.
	getProperty(Lav_BUFFER_POSITION).setDoubleRange(0.0, maxPosition);
}
Example #21
0
void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, bool disposeAfterUse) {
	if (_finished)
		throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): Trying to queue another audio stream, but the QueuingAudioStream is finished.");

	if ((stream->getRate() != getRate()) || (stream->getChannels() != getChannels()))
		throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): stream has mismatched parameters");

	Common::StackLock lock(_mutex);
	_queue.push(StreamHolder(stream, disposeAfterUse));
}
Example #22
0
Channel* Window::getChannel( const ChannelPath& path )
{
    const Channels& channels = getChannels(); 
    EQASSERT( channels.size() > path.channelIndex );

    if( channels.size() <= path.channelIndex )
        return 0;

    return channels[ path.channelIndex ];
}
Example #23
0
void Window::swapBuffers()
{
    const Pipe*         pipe      = static_cast<Pipe*>( getPipe( ));
    const FrameData&    frameData = pipe->getFrameData();
    const eq::Channels& channels  = getChannels();

    if( frameData.useStatistics() && !channels.empty( ))
        EQ_GL_CALL( channels.back()->drawStatistics( ));

    eq::Window::swapBuffers();
}
Example #24
0
void Window::postDelete()
{
    _state = State( _state.get() | STATE_DELETE );
    getConfig()->postNeedsFinish();

    const Channels& channels = getChannels(); 
    for( Channels::const_iterator i = channels.begin(); i!=channels.end(); ++i )
    {
        (*i)->postDelete();
    }    
}
Example #25
0
LogChannel::LogChannel(std::string channelName, std::string prefix) :
  _channelName(channelName),
  _prefix(prefix),
  _error(std::cerr.rdbuf(), _prefix),
  _user(std::cout.rdbuf(), _prefix),
  _debug(std::cout.rdbuf(), _prefix),
  _all(std::cout.rdbuf(), _prefix),
  _level(Global)
{
  getChannels()->insert(this);
}
Example #26
0
void View::updateFrusta()
{
    const Channels& channels = getChannels();
    Vector3f eye;
    const float ratio = _computeFocusRatio( eye );

    Config* config = getConfig();
    FrustumUpdater updater( channels, eye, ratio );

    config->accept( updater );
}
Example #27
0
bool Mixer::addChannel(Identifier channels_id , ValueTree channel_store)
{
  // validate channels group GUI and storage
  Channels* channels = getChannels(channels_id) ;
  if (!channels || !channel_store.isValid()) return false ;

  // create channel GUI and update mixer layout
  bool was_added = channels->addChannel(channel_store) ;
  if (was_added && channels != this->masterChannels) resized() ;

  return was_added ;
}
Example #28
0
bool Mixer::addRemoteUser(ValueTree user_store , ValueTree subscriptions)
{
  // ensure GUI for this user does not already exist
  Identifier user_id = user_store.getType() ; if (getChannels(user_id)) return false ;

  // create remote user GUI
  addChannels(new RemoteChannels(user_store , subscriptions) , user_id) ;

DEBUG_TRACE_ADD_REMOTE_USER

  return true ;
}
Example #29
0
void AudioEngine::mixAudio(Uint8 *pDestBuffer, int destBufferLen)
{
    int numFrames = destBufferLen/(2*getChannels()); // 16 bit samples.

    if (m_AudioSources.size() == 0) {
        return;
    }
    if (!m_pTempBuffer || m_pTempBuffer->getNumFrames() < numFrames) {
        if (m_pTempBuffer) {
            delete[] m_pMixBuffer;
        }
        m_pTempBuffer = AudioBufferPtr(new AudioBuffer(numFrames, m_AP));
        m_pMixBuffer = new float[getChannels()*numFrames];
    }

    for (int i = 0; i < getChannels()*numFrames; ++i) {
        m_pMixBuffer[i]=0;
    }
    {
        lock_guard lock(m_Mutex);
        AudioSourceMap::iterator it;
        for (it = m_AudioSources.begin(); it != m_AudioSources.end(); it++) {
            m_pTempBuffer->clear();
            it->second->fillAudioBuffer(m_pTempBuffer);
            addBuffers(m_pMixBuffer, m_pTempBuffer);
        }
    }
    calcVolume(m_pMixBuffer, numFrames*getChannels(), getVolume());
    for (int i = 0; i < numFrames; ++i) {
        m_pLimiter->process(m_pMixBuffer+i*getChannels());
        for (int j = 0; j < getChannels(); ++j) {
            ((short*)pDestBuffer)[i*2+j]=short(m_pMixBuffer[i*2+j]*32768);
        }
    }
}
Example #30
0
// Add a channel to the timer with a given period
int MuxTimer::add_channel(long period)
{
  // Check if this period is already registered
  for (Channel& channel : getChannels())
  {
    if (channel.period == period)
    {
      // Timer fot his period has already been registered, return the associated id
      INFO_PF("Timer channel with %u ms period already registered", period);

      // Return the associated id
      return channel.id;
    }
  }

  // Check if the timer is not currently running
  if (getStatus())
  {
    // Dump  a log
    ERROR_LG("Timer cannot add new channel in timer, currently running");

    // Return negative result
    return -1;
  }
  else
  {
    // Dump  a log
    INFO_PF("Timer, add new channel to timer with %u ms period", period);

    // Get the new id
    int id = getChannels().size() + 1;

    // Add a new channel to this timer
    getChannels().push_back(Channel(id, period));

    // Return new channel id
    return id;
  }
}