123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754 |
- from app import config, log, register, project_cf, speaker_cf, linphone_cf, player
- import paho.mqtt.client as mqtt
- import json
- from app.app_config import *
- import sys
- from time import sleep
- from threading import Lock
- import os
- import vlc
- import threading
- """
- desc:
- 项目主要功能类
- """
- class Device(object):
- def __init__(self, config = config, player = player):
- self.model = config.model
- self.hostname = config.hostname
- self.ipaddr = config.ipaddr
- self.hard_volume = config.hard_volume
- self.hard_volume_control = config.hard_volume_control
- self.exten = config.exten
- self.exten_password = config.exten_password
- self.server_ipaddr = config.server_ipaddr
- self.mac = config.mac
- self.connect_flags = 1
- self.player_current_volume = config.player_current_volume
- self.init_player_state = config.init_player_state
- self.current_uri = config.current_uri
- self.pull_rtsp = 0
- self.warning_lock = Lock()
- self.error_lock = Lock()
- self.source_error_lock = Lock()
- #添加服务器播放还是本地播放flag 0:服务器播放 1:本地播放
- self.play_action_flag = 0
- self.tmp_init_player_state = 0
- if not self._check_config():
- sys.exit(1)
-
- self.player = player
- self.player.event_manager = self.player.media.event_manager()
- """
- desc:
- 播放器事件回调注册
- Parameters:
- param1 - 播放器事件名
- param2 - 回调函数名
-
- Returns:
- """
- self.player.event_manager.event_attach(vlc.EventType.MediaPlayerEncounteredError, self.MediaPlayerEncounteredError_cb)
- self.player.event_manager.event_attach(vlc.EventType.VlmMediaInstanceStatusError, self.VlmMediaInstanceStatusError_cb)
- self.player.event_manager.event_attach(vlc.EventType.MediaPlayerPlaying, self.MediaPlayerPlaying_cb)
- self.player.event_manager.event_attach(vlc.EventType.MediaPlayerPaused, self.MediaPlayerPaused_cb)
- self.player.event_manager.event_attach(vlc.EventType.MediaPlayerStopped, self.MediaPlayerStopped_cb)
- self.vlc_error_count = 0
- self.vlc_source_error_count = 0
- self.vlc_warning_count = 0
- self.mqttClient = mqtt.Client(client_id = self.mac, clean_session = True)
- self.mqttClient.username_pw_set(username=self.exten, password=self.exten_password)
- self.mqttClient.on_connect = self.on_connect
-
- # 注册监听器
- def add_callback(self, event_type, callback):
- pass
- # 移除监听器
- def remove_callback(self, event_type, callback):
- pass
- def MediaPlayerEncounteredError_cb(self, event):
- # self.set_vlc_source_error_count(self.get_vlc_source_error_count() + 1)
- # if self.get_vlc_source_error_count() > VLC_SOURCE_ERROR_COUNT:
- # self.set_vlc_source_error_count(0)
- # return
- # else:
- # log.logger.error("MediaPlayerEncounteredError_cb")
- # sleep(2)
- # log.logger.info("Replay uri:%s" % (self.current_uri))
- # t = threading.Thread(target = self.player.play, args = (self.current_uri,))
- # t.setDaemon(True)
- # t.start()
- # log.logger.info("Replay finished!")
- log.logger.error("Player play error")
- def VlmMediaInstanceStatusError_cb(self, event):
- log.logger.error("VlmMediaInstanceStatusError_cb")
- """
- desc:
- 开始播放事件回调,控制声音渐入
- """
- def MediaPlayerPlaying_cb(self, event):
- log.logger.error("MediaPlayerPlaying_cb")
- t = threading.Thread(target = self.FadeIn, args = (0, self.player_current_volume,))
- t.setDaemon(True)
- t.start()
- log.logger.info("Set volume FadeIn finished!")
- def MediaPlayerPaused_cb(self, event):
- log.logger.error("MediaPlayerPaused_cb")
- def MediaPlayerStopped_cb(self, event):
- log.logger.error("MediaPlayerStopped_cb")
- """
- desc:
- 播放器声音渐入实现函数,从low_volume音量过渡到high_volume
-
- Parameters:
- param1 - 低音量
- param2 - 高音量
- """
- def FadeIn(self, low_volume, high_volume):
- self.player.set_volume(low_volume)
- per_volume = (high_volume - low_volume)//10
- tmp_volume = low_volume + per_volume
- i = 0
- while i < 10:
- sleep(0.1)
- if i == 9:
- self.player.set_volume(high_volume)
- else:
- self.player.set_volume(tmp_volume)
- tmp_volume = tmp_volume + per_volume
- i = i + 1
- return True
- """
- desc:
- 播放器声音渐出实现函数,从high_volume音量过渡到low_volume
-
- Parameters:
- param1 - 高音量
- param2 - 低音量
- """
- def FadeOut(self, low_volume, high_volume):
- per_volume = (high_volume - low_volume)//10
- tmp_volume = high_volume - per_volume
- i = 0
- while i < 9:
- sleep(0.1)
- if i == 8:
- self.player.set_volume(low_volume)
- else:
- self.player.set_volume(tmp_volume)
- tmp_volume = tmp_volume - per_volume
- i = i + 1
- return True
- """
- desc:
- 系统信号处理函数,主要处理键盘输入,如ctrl+c等
-
- Parameters:
- param1 - 信号数字
- param2 - 处理方法
- """
- def singal_handler(self, singal_num, handler):
- self.mqttClient.disconnect()
- self.connect_flags = 0
- self.stop_pull_rtsp()
- log.logger.info("Mqtt disconnect now!")
- sys.exit(0)
-
- """
- desc:
- 设置播放器警告日志数量
-
- Parameters:
- param1 - 数量
- """
- def set_vlc_warning_count(self, value):
- self.warning_lock.acquire()
- self.vlc_warning_count = value
- self.warning_lock.release()
-
- def get_vlc_warning_count(self):
- return self.vlc_warning_count
- def set_vlc_error_count(self, value):
- self.error_lock.acquire()
- self.vlc_error_count = value
- self.error_lock.release()
-
- def get_vlc_error_count(self):
- return self.vlc_error_count
-
- def set_vlc_source_error_count(self, value):
- self.source_error_lock.acquire()
- self.vlc_source_error_count = value
- self.source_error_lock.release()
-
- def get_vlc_source_error_count(self):
- return self.vlc_source_error_count
- """
- desc:
- 连接mqtt服务器
- """
- def run(self):
- while self.connect_flags:
- try:
- log.logger.info("Mqtt to %s:%d, connectting..." % (self.server_ipaddr, SERVER_MQTT_PORT))
- self.mqttClient.connect(self.server_ipaddr, SERVER_MQTT_PORT, MQTT_CONNECT_TIMEOUT)
- self.connect_flags = 0
- except:
- log.logger.error("Mqtt connect to %s:%d error" % (self.server_ipaddr, SERVER_MQTT_PORT))
- log.logger.error("Mqtt reconnect...")
- sleep(RETRY_SEC)
- self.mqttClient.loop_start()
- self.mqttClient.on_message = register.recieve_run
- self.mqttClient.on_subcribe = self.on_subcribe
- self.mqttClient.on_disconnect = self.on_disconnect
- self.mqttClient.on_publish = self.on_publish
- self.mqttClient.on_socket_close = self.on_socket_close
- self.mqttClient.subscribe(TOPIC_COMMAND, MQTT_QOS)
- return True
-
- """
- desc:
- mqtt连接事件回调函数
- """
- def on_connect(self, client, userdata, flags, rc):
- log.logger.info(mqtt.connack_string(rc))
- self._player_reconnect()
- init_data = self._get_init_data()
- self.mqttClient.publish(TOPIC_EVENT, json.dumps(init_data).encode("utf-8"), MQTT_QOS)
- log.logger.info("Publish data: %s" % (init_data))
- return True
- """
- desc:
- 播放器重新连接
- """
- def _player_reconnect(self):
- if self.current_uri != "" and self.init_player_state == 1:
- self.player.play(self.current_uri)
- log.logger.info("Player reconnect finished!")
- sleep(1)
- else:
- log.logger.info("Not need reconnect!")
- return True
-
- """
- desc:
- 组装mqtt连接到的服务器时需上报的初始化数据
- """
- def _get_init_data(self):
- init_data = {}
- data = {}
- data.setdefault(SOLF_VOLUME, self.player_current_volume)
- data.setdefault(HARD_VOLUME, self.hard_volume)
- data.setdefault("hard-volume-control", self.hard_volume_control)
- data.setdefault(EXTEN, self.exten)
- data.setdefault(DEVICE_MODEL, self.model)
- status = self.player.get_state()
- if status == 1:
- data.setdefault(STATUS, PLAYER_PLAYING)
- data.setdefault("url", self.current_uri)
- elif status == 0:
- data.setdefault(STATUS, PLAYER_PAUSE)
- elif status == -1:
- data.setdefault(STATUS, PLAYER_IDLE)
- else:
- data.setdefault(STATUS, PLAYER_ERROR)
- init_data.setdefault(ACTION_NAME, "init")
- init_data.setdefault(DATA, data)
- return init_data
-
- """
- desc:
- 设置播放器音量
-
- Parameters:
- param1 - 音量
- param2 - 类型
- """
- def set_soft_volume(self, volume, type = "default"):
- old_volume = self.player_current_volume
- self.player_current_volume = volume
- project_cf.read(PROJECT_CONFIG)
- project_cf.set("general", "player_init_volume", str(volume))
- with open(PROJECT_CONFIG, "w+") as f:
- project_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- if self.player.get_state() == 1:
- if old_volume > volume:
- self.FadeOut(volume, old_volume)
- elif old_volume < volume:
- self.FadeIn(old_volume, volume)
- else:
- pass
- else:
- self.player.set_volume(volume)
- return True
- """
- desc:
- 设置系统相关数据
-
- Parameters:
- param1 - 相关数据
- """
- def set_service_settings(self, data):
- if "soft-volume" in data:
- self.player_current_volume = int(data.get("soft-volume"))
- if "hard-volume" in data:
- self.set_hard_volume(int(data.get("hard-volume")))
- if "hard-volume-control" in data:
- self.set_hard_volume_control(data.get("hard-volume-control"))
- return True
- """
- desc:
- 开始拉取本地摄像头的rtsp流并推送到服务器
-
- Parameters:
- param1 - 本地摄像头rtsp地址
- param2 - 服务器的rtsp地址
- """
- def start_pull_rtsp(self, src, dst):
- if not src:
- log.Logger.error("src not found")
- return False
- if not dst:
- log.Logger.error("dst not found")
- return False
- tmp_pull_rtsp = self.pull_rtsp
- self.stop_pull_rtsp()
- self.pull_rtsp = tmp_pull_rtsp
- sleep(1)
- os.system("%s %s %s > /dev/null 2>&1 &" % (RTSP_PUSHER, src, dst))
- log.logger.info("%s %s %s > /dev/null 2>&1 &" % (RTSP_PUSHER, src, dst))
- self.pull_rtsp = self.pull_rtsp + 1
- log.logger.info("self.pull_rtsp:%d" % (self.pull_rtsp))
- return True
- """
- desc:
- 停止拉取本地摄像头的rtsp流
- """
- def stop_pull_rtsp(self):
- os.system("/usr/bin/killall rtsp_pull_push > /dev/null 2>&1 &")
- self.pull_rtsp = 0
- return True
- """
- desc:
- 设置系统的音量
-
- Parameters:
- param1 - 系统音量值
- """
- def set_hard_volume(self, volume):
- if volume and volume >= 0 and volume <= 10:
- real_hard_volume = volume * 5 + 75
- try:
- os.system("/usr/bin/amixer sset 'Headphone',0 %d > /dev/null 2>&1 &" % (real_hard_volume))
- speaker_cf.read(SPEAKER_CONFIG_FILE)
- speaker_cf.set("system", "volume_out", str(volume))
- with open(SPEAKER_CONFIG_FILE, "w+") as f:
- speaker_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- self.hard_volume = volume
- except ERROR:
- log.logger.error("Set hard volume error:\n%s" % (ERROR))
- return False
- else:
- log.logger.error("Parameter volume not exist")
- return False
- return True
-
- """
- desc:
- 设置强控,不允许通过硬件按键修改系统音量
-
- Parameters:
- param1 - 强控开关
- """
- def set_hard_volume_control(self, value):
- if value:
- try:
- speaker_cf.read(SPEAKER_CONFIG_FILE)
- speaker_cf.set("volume", "hard_volume_control", value)
- with open(SPEAKER_CONFIG_FILE, "w+") as f:
- speaker_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- self.hard_volume_control = value
- except ERROR:
- log.logger.error("Set hard volume control value:\n%s" % (ERROR))
- return False
- else:
- log.logger.error("Set hard volume control value not exist")
- return False
- return True
- """
- desc:
- 设置系统分机信息
-
- Parameters:
- param1 - 服务器地址
- param2 - 用户名(分机号)
- param3 - 分机密码
- """
- def set_exten(self, host, exten, password):
- if host and exten and password:
- try:
- linphone_cf.read(LINPHONE_CONFIG_FILE)
- linphone_cf.set("auth_info_0", "username", exten)
- linphone_cf.set("auth_info_0", "passwd", password)
- reg_proxy = "<sip:%s>" % (host)
- reg_identity = "sip:%s@%s" % (exten, host)
- linphone_cf.set("proxy_0", "reg_proxy", reg_proxy)
- linphone_cf.set("proxy_0", "reg_identity", reg_identity)
- with open(LINPHONE_CONFIG_FILE, "w+") as f:
- linphone_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- except ERROR:
- log.logger.error("Set exten error:\n%s" % (ERROR))
- return False
- else:
- log.logger.error("Set exten value not full")
- return False
-
- return True
-
- """
- desc:
- vlc播放指定数据
-
- Parameters:
- param1 - 播放数据
- """
- def play(self, data):
- if "url" in data:
- url = data.get("url")
- else:
- log.logger.warning("Url not found!")
- return False
- if "soft-volume" in data:
- self.set_soft_volume(int(data.get("soft-volume")))
-
- if "hard-volume" in data:
- self.set_hard_volume(int(data.get("hard-volume")))
- if "hard-volume-control" in data:
- self.set_hard_volume_control(data.get("hard-volume-control"))
- try:
- self.init_player_state = 1
- self.current_uri = url
- self.play_action_flag = 0
- try:
- project_cf.read(PROJECT_CONFIG)
- project_cf.set("general", "init_player_state", str(self.init_player_state))
- project_cf.set("general", "current_uri", str(self.current_uri))
- with open(PROJECT_CONFIG, "w+") as f:
- project_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- except ERROR:
- log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
- return False
- self.player.stop()
- self.player.play(url)
- except:
- log.logger.error("Player play uri:%s is error" % (url))
- return False
- return True
-
- """
- desc:
- 播放器暂停
-
- Parameters:
- param1 - 暂停模式
- """
- def pause(self, value):
- self.init_player_state = 0
- if value == "stop":
- try:
- self.player.stop()
- except:
- log.logger.error("Player pause(stop) is error")
- else:
- try:
- self.player.pause()
- except:
- log.logger.error("Player pause is error")
-
- try:
- project_cf.read(PROJECT_CONFIG)
- project_cf.set("general", "init_player_state", str(self.init_player_state))
- with open(PROJECT_CONFIG, "w+") as f:
- project_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- except ERROR:
- log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
-
- return True
-
- """
- desc:
- 播放器恢复播放
-
- Parameters:
- param1 - 恢复数据
- """
- def resume(self, value):
- self.init_player_state = 1
- try:
- project_cf.read(PROJECT_CONFIG)
- project_cf.set("general", "init_player_state", str(self.init_player_state))
- with open(PROJECT_CONFIG, "w+") as f:
- project_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- except ERROR:
- log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
-
- if self.player.get_state() == 1:
- return True
- if value == "play":
- data = {}
- data.setdefault("url", self.current_uri)
- try:
- self.play(data)
- except:
- log.logger.error("Player resume(play) is error")
- else:
- try:
- self.player.resume()
- except:
- log.logger.error("Player resume is error")
-
- return True
-
- """
- desc:
- 播放器停止播放
- """
- def stop(self):
- self.init_player_state = -1
- self.current_uri = ""
- self.play_action_flag = 0
- try:
- self.FadeOut(0, self.player_current_volume)
- self.player.stop()
- try:
- project_cf.read(PROJECT_CONFIG)
- project_cf.set("general", "init_player_state", str(self.init_player_state))
- project_cf.set("general", "current_uri", "")
- with open(PROJECT_CONFIG, "w+") as f:
- project_cf.write(f, space_around_delimiters=False)
- os.system("sync")
- except ERROR:
- log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
- return False
- except:
- log.logger.error("Player stop is error")
- return False
- return True
-
- def on_subcribe(self, client, userdata, mid, granted_qos):
- pass
- def on_publish(self, client, userdata, mid):
- pass
- def on_disconnect(self, client, userdata, rc):
- log.logger.info("Mqtt disconnect!")
- """
- desc:
- 检测系统的必要配置信息
- """
- def _check_config(self):
- if not self.model:
- log.logger.error("Model not found!")
- return False
- elif not self.mac:
- log.logger.error("Mac not found!")
- return False
- elif not self.server_ipaddr:
- log.logger.error("Server Ipaddr not found!")
- return False
- elif not self.exten:
- log.logger.error("Extension not found!")
- return False
- elif self.hard_volume < 0:
- log.logger.error("Hard Volume error!")
- return False
- else:
- return True
-
- """
- desc:
- 监测系统状态变化,如音量,播放状态等
- """
- def _check_variable(self):
- old_soft_volume = self.player_current_volume
- old_hard_volume = self.hard_volume
- old_exten = self.exten
- old_player_state = self.player.get_state()
- old_hard_volume_control = self.hard_volume_control
- old_pull_rtsp = self.pull_rtsp
- while True:
- sleep(CHECK_INTERVAL)
- data = {}
- event = {}
- event.setdefault(ACTION_NAME, TOPIC_UPDATE)
- event.setdefault(DATA, data)
- new_soft_volume = self.player_current_volume
- if old_soft_volume != new_soft_volume:
- old_soft_volume = new_soft_volume
- data.setdefault(SOLF_VOLUME, new_soft_volume)
-
- project_cf.read(PROJECT_CONFIG)
- new_hard_volume = int(speaker_cf.get("system", "volume_out"))
- if old_hard_volume != new_hard_volume:
- old_hard_volume = new_hard_volume
- data.setdefault(HARD_VOLUME, new_hard_volume)
-
- linphone_cf.read(LINPHONE_CONFIG_FILE)
- new_exten = linphone_cf.get("auth_info_0", "username")
- if old_exten != new_exten:
- old_exten = new_exten
- data.setdefault(EXTEN, new_exten)
- if self.init_player_state == 1 and self.player.get_state() != 1:
- if self.current_uri != "":
- self._player_reconnect()
- new_player_state = self.player.get_state()
- if old_player_state != new_player_state and self.play_action_flag == 0:
- old_player_state = new_player_state
- if new_player_state == -1:
- player_status = PLAYER_IDLE
- elif new_player_state == 0:
- player_status = PLAYER_PAUSE
- elif new_player_state == 1:
- player_status = PLAYER_PLAYING
- else:
- player_status = PLAYER_ERROR
- data.setdefault(STATUS, player_status)
-
- speaker_cf.read(SPEAKER_CONFIG_FILE)
- new_hard_volume_control = speaker_cf.get("volume", "hard_volume_control")
- if old_hard_volume_control != new_hard_volume_control:
- old_hard_volume_control = new_hard_volume_control
- data.setdefault(HARD_VOLUME_CONTROL, new_hard_volume_control)
-
- new_pull_rtsp = self.pull_rtsp
- if old_pull_rtsp != new_pull_rtsp:
- old_pull_rtsp = new_pull_rtsp
- if new_pull_rtsp != 0:
- data.setdefault("pull-rtsp", 1)
- else:
- data.setdefault("pull-rtsp", 0)
-
- if event.get(DATA) != {}:
- try:
- self.mqttClient.publish(TOPIC_EVENT, json.dumps(event).encode('utf-8'), MQTT_QOS)
- log.logger.info("Publish event:%s" % (event))
- except ERROR:
- log.logger.error("Publish event:\n%s" % (ERROR))
- """
- desc:
- 监测fifo
- """
- def _fifo(self):
- if not os.path.exists(FIFO_PATH):
- os.mkfifo(FIFO_PATH)
-
- rf = os.open(FIFO_PATH, os.O_RDWR)
-
- while True:
- data = os.read(rf, 64)
- data = data.decode("utf-8")
- log.logger.info("received msg from fifo:%s" % (data))
- if data == "0":
- if self.player.get_state() == 1:
- self.play_action_flag = 1
- self.tmp_init_player_state = self.init_player_state
- self.init_player_state = 0
- self.player.stop()
- elif data == "1":
- self.play_action_flag = 0
- self.init_player_state = self.tmp_init_player_state
- else:
- log.logger.error("No support this action!")
- os.close(rf)
-
- """
- desc:
- 启动监测线程
- """
- def check_start(self):
- try:
- t = threading.Thread(target = self._check_variable, args = ())
- t.setDaemon(True)
- t.start()
- return True
- except ERROR:
- log.logger.error(ERROR)
- """
- desc:
- 启动fifo监测
- """
- def check_fifo_start(self):
- try:
- t = threading.Thread(target = self._fifo, args = ())
- t.setDaemon(True)
- t.start()
- return True
- except ERROR:
- log.logger.error(ERROR)
- """
- desc:
- socket断线回调
- """
- def on_socket_close(self, client, userdata, sock):
- log.logger.error("Socket error(disconnect) occur!")
|