?? hxplayercontrol.cpp
字號(hào):
/*************************************************************************** * Copyright (C) 2006 Paul Cifarelli <paul@cifarelli.net> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//*************************************************************************** basically this implements a rudamentary rpc mechanism so the we can have each player in a separate process. this is solely done to implement a reliable crossfade (or more precicely, put the crossfade in the hands of the alsa guys ***************************************************************************/#include <sys/time.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <iostream>#include <sys/mman.h>using namespace std;#include "hxplayercontrol.h"class HSPPlayerControlled : public HelixSimplePlayer{public: HSPPlayerControlled(PlayerControl *pcntl, int index) : m_pcntl(pcntl), m_index(index) {} virtual ~HSPPlayerControlled() {} virtual void notifyUser(unsigned long code, const char *moreinfo, const char *moreinfourl); virtual void interruptUser(unsigned long code, const char *moreinfo, const char *moreinfourl); virtual void onContacting(const char *host); virtual void onBuffering(int percentage);private: PlayerControl *m_pcntl; int m_index;};void HSPPlayerControlled::notifyUser(unsigned long code, const char *moreinfo, const char *moreinfourl){ m_pcntl->sendnotifyuser(code, moreinfo, moreinfourl);}void HSPPlayerControlled::interruptUser(unsigned long code, const char *moreinfo, const char *moreinfourl){ m_pcntl->sendinterruptuser(code, moreinfo, moreinfourl);}void HSPPlayerControlled::onContacting(const char *host){ m_pcntl->sendcontacting(host);}void HSPPlayerControlled::onBuffering(int percentage){ m_pcntl->sendbuffering(percentage);}PlayerControl::PlayerControl() : m_eq_enabled(false), m_preamp(0), m_err(0), iamparent(0), m_index(0), nNumPlayers(0), m_inited(false), m_api( HelixSimplePlayer::OSS ), m_device(0), mimehead(0), mimelistlen(0), m_numPlugins(0), m_pluginInfo(0){ memset(m_children, 0, sizeof(m_children));}PlayerControl::~PlayerControl(){ tearDown(); print2stderr("In PlayerControl::~PlayerControl(), m_index=%d\n", m_index); delete m_device; if (pmapped) munmap(pmapped, sizeof(stateStuff) * 2);}// init functionsvoid PlayerControl::init(const char *corelibpath, const char *pluginslibpath, const char *codecspath, int numPlayers){ int err; iamparent = 0; nNumPlayers = numPlayers; m_err = 0; print2stderr("In PlayerControl::init(), m_api=%d, m_device=%s\n", m_api, m_device ? m_device : "DEVICE NOT SET"); if (numPlayers > 2) // it's impossible { m_err = -1; return; } memset(&m_children, 0, numPlayers * sizeof(struct playerChildren)); m_inited = false; // create a shared memory region for state like stuff if ( MAP_FAILED == (pmapped = (stateStuff *) mmap( (void *) statestuff, sizeof(stateStuff) * 2, PROT_READ | PROT_WRITE,#ifdef __linux__ MAP_SHARED | MAP_ANONYMOUS,#else MAP_SHARED | MAP_ANON,#endif -1, 0)) ) pmapped = 0; // we do this the old fashioned way, so that we don't have to include an executable with our plugin... for (int i = 0; i < numPlayers; i++) { if (pmapped) { m_children[i].current_time = &(pmapped[i].current_time); m_children[i].duration = &(pmapped[i].duration); m_children[i].md = &(pmapped[i].md); m_children[i].m_current = &(pmapped[i].m_current); m_children[i].m_consumed = &(pmapped[i].m_consumed); //m_children[i].q = pmapped[i].q; //for (int j=0; j<NUM_SCOPEBUFS; j++) //{ // m_children[i].q[j].allocd = false; // m_children[i].q[j].buf = pmapped[i].b[j]; //} } err = pipe(m_children[i].m_pipeA); err |= pipe(m_children[i].m_pipeB); if ( !err && (iamparent = fork()) ) { // parent print2stderr("%%%%%% parent initializes player %d\n", i); // parent's m_pid remains 0 m_children[i].m_pid = iamparent; close(m_children[i].m_pipeA[1]); // parent uses A for reading close(m_children[i].m_pipeB[0]); // and B for writing } else if (!err) { // child cerr << "%%%%%% child initializes as player " << i << endl;; m_index = i; // child's index is saved close(m_children[i].m_pipeA[0]); // child uses A for writing close(m_children[i].m_pipeB[1]); // and B for reading break; } } if (!iamparent) // children stay here, parents return { int rfd = m_children[m_index].m_pipeB[0]; int wfd = m_children[m_index].m_pipeA[1]; int n; struct timeval timeout; HSPPlayerControlled *player = 0; bool playing = false; player = new HSPPlayerControlled(this, m_index); timeout.tv_sec = 0; timeout.tv_usec = 10000; fd_set rdset, wrset; FD_ZERO(&rdset); FD_ZERO(&wrset); FD_SET(rfd, &rdset); FD_SET(wfd, &wrset); // really should check to see if we can write, but not gonna while ( 1 ) { FD_SET(rfd, &rdset); n = select(rfd + 1, &rdset, 0, 0, &timeout); if ( FD_ISSET(rfd, &rdset) ) { msgid m; unsigned char buf[65536]; int sz = 0; if (getmessage(rfd, m, buf, sz) && player) { switch (m) { case INIT: cerr << "INIT\n"; if (!sz) { player->setOutputSink(m_api); if (m_device) player->setDevice(m_device); player->init(corelibpath, pluginslibpath, codecspath, 1); m_inited = true; if (!m_index) // only player 0 need send the mime and plugin stuff { sendplugins(wfd, player); sendmimetypes(wfd, player); } cerr << "%%%%%% player " << m_index << " child sends ready\n"; sendready(wfd); } else cerr << "CHILD " << m_index << " sz not right in INIT, sz=" << sz << endl; break; case SETURL: { bool islocal = (bool) buf[0]; int len = strlen((const char *)&buf[1]); // not that this would prevent a crash... if (m_inited) { cerr << "CHILD " << m_index << " setURL for " << (const char *)&buf[1] << ",islocal=" << islocal << ",len=" << len << endl; if (sz == len + 2) player->setURL((const char *)&buf[1], 0, islocal); // remember, we sent the null... else cerr << "CHILD " << m_index << " sz not right in SETURL, sz=" << sz << endl; } } break; case START: { bool fadein = (bool) buf[0]; unsigned long fadetime; if (m_inited) { if (pmapped) *m_children[m_index].current_time = 0; if (sz == sizeof(unsigned long) + 1) { cerr << "CHILD " << m_index << " gets START\n"; memcpy((void *)&fadetime, (void *)&buf[1], sizeof(unsigned long)); playing = true; player->start(0, fadein, fadetime); } else cerr << "CHILD " << m_index << " sz not right in START, sz=" << sz << endl; } } break; case STOP: if (m_inited) if (!sz) { player->stop(); playing = false; cerr << "CHILD " << m_index << " gets STOP\n"; } else cerr << "CHILD " << m_index << " sz not right in STOP, sz=" << sz << endl; break; case PAUSE: if (m_inited) if (!sz) player->pause(); else cerr << "CHILD " << m_index << " sz not right in PAUSE, sz=" << sz << endl; break; case RESUME: if (m_inited) if (!sz) player->resume(); else cerr << "CHILD " << m_index << " sz not right in RESUME, sz=" << sz << endl; break; case SEEK: if (m_inited) if (sz == sizeof(unsigned long)) { unsigned long pos; memcpy( (void *) &pos, (void *) buf, sizeof(unsigned long) ); if (pos < player->duration(0)) player->seek(pos, 0); } else cerr << "CHILD " << m_index << " sz not right in SEEK, sz=" << sz << endl; break; case SETVOLUME: { if (m_inited) if (sz == sizeof(unsigned long)) { memcpy( (void *) &m_volume, (void *) buf, sizeof(unsigned long)); cerr << "CHILD: received setvolume request " << m_volume <<endl;; player->setVolume(m_volume); } else cerr << "CHILD " << m_index << " sz not right in SETVOLUME, sz=" << sz << endl; } break; case OUTPUTSINK: if (m_inited) if (sz == 1) { m_api = (HelixSimplePlayer::AUDIOAPI) buf[0]; cerr << "CHILD: received OUTPUTSINK: " << m_api <<endl;; } else cerr << "CHILD " << m_index << " sz not right in OUTPUTSINK, sz=" << sz << endl; break; case DEVICE: { char* dev = strdup((const char*) buf); if (m_inited) if ((unsigned)sz == strlen(dev) + 1) { cerr << "CHILD " << m_index << " gets device " << dev << endl; setDevice( dev ); } else cerr << "CHILD " << m_index << " sz not right in DEVICE, sz=" << sz << endl; free(dev); } break; case SETFADE: { if (m_inited) if (sz == sizeof(unsigned long) + 1) { bool fadeout; unsigned long fadelength; fadeout = (bool) buf[0]; memcpy((void *) &fadelength, (void *) &buf[1], sizeof(unsigned long)); player->setFadeout(fadeout, fadelength, 0); } else cerr << "CHILD " << m_index << " sz not right in SETFADE, sz=" << sz << endl; } break; case ENABLEEQ: { if (m_inited) if (sz == 1) { m_eq_enabled = (bool) buf[0]; player->enableEQ(m_eq_enabled); cerr << "CHILD " << m_index << " enables EQ\n"; } else cerr << "CHILD " << m_index << " sz not right in ENABLEEQ, sz=" << sz << endl; } break; case UPDATEEQGAINS: { int i, n, k; cerr << "UPDATEGAINS\n"; if (m_inited) { if (sz >= 2) { memcpy( (void *) &m_preamp, (void *) buf, sizeof(m_preamp) ); memcpy( (void *) &n, (void *) &buf[ sizeof(m_preamp) ], sizeof(int) ); player->m_preamp = m_preamp; } else cerr << "CHILD " << m_index << " sz not right in UPDATEEQGAINS, sz=" << sz << endl; if ((unsigned)sz == sizeof(m_preamp) + sizeof(int) + n * sizeof(int)) { if (n > 0) { m_equalizerGains.resize(n); cerr << "CHILD " << m_index << " receives " << n << " equalizer gains\n"; for (i=0; i<n; i++) { memcpy( (void *) &k, (void *) &buf[ sizeof(m_preamp) + (i+1)*sizeof(int) ], sizeof(int) ); m_equalizerGains[i] = k; } player->m_equalizerGains = m_equalizerGains; if (!m_eq_enabled) player->enableEQ(true); player->updateEQgains(); player->enableEQ(m_eq_enabled); } } else cerr << "CHILD " << m_index << " sz not right in UPDATEEQGAINS, sz=" << sz << endl; } } break; case SCOPECLEAR: if (m_inited) { player->clearScopeQ(0); if (pmapped) *m_children[m_index].m_consumed = *m_children[m_index].m_current = 0; } break; case TEARDOWN: if (!sz) { cerr << "CHILD: " << m_index << " received shutdown request\n"; player->stop(0); delete player; raise(15); exit(0); } else cerr << "CHILD " << m_index << " sz not right in TEARDOWN, sz=" << sz << endl; break; default: // send an error to the parent cerr << "CHILD " << m_index << " received unhandled message, sz=" << sz << endl; break; } } else { cerr << "CHILD " << m_index << " gets EOD\n"; break; } } if (m_inited) { player->dispatch(); if (playing && player->done(0)) {
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -