You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Odoo中实现单设备及跨设备播放扫码缺品提示音

解决方案:Odoo单设备与跨设备声音播放实现

一、先拆解原代码的核心问题

你当前的代码是直接在Odoo服务端执行音频生成和播放逻辑——这就是为什么单设备(比如本地开发时,服务端和客户端在同一机器)能正常出声,但多设备场景下,声音其实是在服务器上播放的,扫码的客户端设备根本听不到。要实现跨设备播放,必须把音频播放逻辑转移到客户端浏览器中。


二、单设备场景的优化方案

如果只需要在服务端所在设备播放声音,我们先修正原代码的语法问题,并添加必要的异常处理和依赖导入:

import math
import pyaudio
from odoo import api, models

class YourModel(models.Model):
    _inherit = 'your.model.name'  # 替换成你实际继承的业务模型

    @api.multi
    def _product_sound(self):
        try:
            PyAudio = pyaudio.PyAudio()
            bitrate = 8000
            frq = 500
            LENGTH = 2

            if frq > bitrate:
                bitrate = frq + 100

            numberofframe = int(bitrate * LENGTH)
            restframe = numberofframe % bitrate
            wave = ''
            for x in range(numberofframe):
                wave += chr(int(math.sin(x / ((bitrate / frq) / math.pi)) * 124 + 128))
            for x in range(restframe):
                wave += chr(128)

            p = PyAudio()
            stream = p.open(
                format=p.get_format_from_width(1),
                channels=1,
                rate=bitrate,
                output=True
            )
            stream.write(wave)
            stream.stop_stream()
            stream.close()
            p.terminate()
        except Exception as e:
            # 记录错误日志,方便排查问题
            self.env['ir.logging'].sudo().create({
                'name': 'Product Sound Playback Error',
                'type': 'server',
                'message': str(e),
                'level': 'error',
            })

单设备场景注意点:

  • 确保Odoo服务器所在设备安装了pyaudio依赖:执行pip install pyaudio
  • 仅适用于服务端和客户端在同一机器的场景,比如本地开发或单工位专属设备

三、跨设备(多客户端)场景的正确实现

要让每个扫码的客户端设备播放声音,必须用前端JavaScript触发浏览器的音频播放,下面是两种常用方案:

方式1:预加载自定义音频文件播放

适合使用固定提示音的场景,步骤如下:

  1. 在模块的static/src/sounds目录下放入你的提示音文件(比如not_found.wav)
  2. 在XML视图中注入音频资源:
<template id="assets_backend" inherit_id="web.assets_backend">
    <xpath expr="." position="inside">
        <audio id="product_not_found_sound" preload="auto">
            <source src="/your_module/static/src/sounds/not_found.wav" type="audio/wav"/>
        </audio>
    </xpath>
</template>
  1. 在Python方法中触发前端动作:
from odoo import api, models

class YourModel(models.Model):
    _inherit = 'your.model.name'

    @api.multi
    def _product_sound(self):
        # 通知前端播放声音
        return {
            'type': 'ir.actions.client',
            'tag': 'play_product_not_found_sound',
        }
  1. 在JS文件中注册播放动作:
odoo.define('your_module.sound_playback', function(require) {
    "use strict";

    var core = require('web.core');

    core.action_registry.add('play_product_not_found_sound', function() {
        var audio = document.getElementById('product_not_found_sound');
        if (audio) {
            audio.currentTime = 0; // 重置播放位置,确保每次从头播放
            audio.play().catch(error => console.error("播放失败:", error));
        }
    });
});

方式2:动态生成音频并播放

如果需要像原代码那样生成正弦波提示音,可以在Python中生成音频数据转成Base64,再传递给前端播放:

import math
import base64
from io import BytesIO
import wave
from odoo import api, models

class YourModel(models.Model):
    _inherit = 'your.model.name'

    @api.multi
    def _product_sound(self):
        # 生成正弦波音频数据
        bitrate = 8000
        frq = 500
        duration = 2
        sample_width = 1
        channels = 1

        if frq > bitrate:
            bitrate = frq + 100

        num_frames = int(bitrate * duration)
        rest_frames = num_frames % bitrate

        # 生成音频帧
        frames = bytearray()
        for x in range(num_frames):
            sample = int(math.sin(x / ((bitrate / frq) / math.pi)) * 124 + 128)
            frames.append(sample)
        for x in range(rest_frames):
            frames.append(128)

        # 写入WAV格式并转Base64
        wav_buffer = BytesIO()
        with wave.open(wav_buffer, 'wb') as wav_file:
            wav_file.setnchannels(channels)
            wav_file.setsampwidth(sample_width)
            wav_file.setframerate(bitrate)
            wav_file.writeframes(frames)
        wav_base64 = base64.b64encode(wav_buffer.getvalue()).decode('utf-8')
        audio_data_url = f"data:audio/wav;base64,{wav_base64}"

        # 传递给前端播放
        return {
            'type': 'ir.actions.client',
            'tag': 'play_dynamic_sound',
            'params': {'audio_url': audio_data_url}
        }

对应的JS代码:

odoo.define('your_module.dynamic_sound', function(require) {
    "use strict";

    var core = require('web.core');

    core.action_registry.add('play_dynamic_sound', function(action) {
        var audio = new Audio(action.params.audio_url);
        audio.currentTime = 0;
        audio.play().catch(error => console.error("动态音频播放失败:", error));
    });
});

跨设备场景关键注意事项

  • 浏览器有自动播放限制,必须确保播放动作是由用户交互触发的(比如扫码操作本身就是用户交互,符合要求)
  • 自定义音频文件需要在模块的__manifest__.py中声明静态资源,确保Odoo能正确加载

内容的提问来源于stack exchange,提问作者Harshit Trivedi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:25:10