齢寿天任せ

写真付きで日記や趣味を書くならgooブログ

ESP32でWiFiとBluetooth(A2DP)は同時に使えるか

2023-09-17 15:20:22 | 電子工作

以前、ESP32によるインターネットラジオを製作したが、これはDACをI2Sで接続し、スピーカーから音を出す物だった。ESP32はWiFiとBluetoothを搭載しているので、それらを同時に使えば、ESP32でインターネットラジオを受信し、それをA2DPでBluetoothスピーカーに送って音を出すことができるはずである(スマホで普通にやってること)。事例がないかを調べて見た。

GithubにESP32を色々な方式のプレイヤーにするコードの実装例があった。その中に、SDカードモジュールを使い、A2DPで接続したBluetoothスピーカーから音を出すプレイヤーと、インターネットラジオを受信し、I2Sで接続したDACから音を出すプレイヤーの例を見つけた。これらを組み合わせれば、所期の目的を達成できそうだと思った。

しかしながら、結論からいうと、WiFiとA2DPを同時に動作させることはできなかった。A2DPを接続するとWiFiが繋がらない。WiFiを接続するとA2DPの接続でリセットエラーになる等、(このケースでは)同時には動作しなかった。

以下は試行錯誤の報告である。実装コード(ライブラリ)は洗練されていて、各種のプレーヤーが簡単に実装できるようになっており、最初の2例は動作を確認したので参考になると思う。

インターネットラジオを受信し、I2Sで接続したDACから音を出すプレイヤー

以下にスケッチを示す。上記の実装例からは、ボリューム(音量)や接続先のURLを変更するコードは省略している。ライブラリは、pschatzmannさんのライブラリを、ZIP形式でダウンロードし、ArduinoIDEのライブラリ管理からインストールする。「*wifi」と「*password」の部分は、利用しているWiFiのものを指定する。DACはUDA1334かPCM5102のモジュールが使える。ESP32との接続方法は、上記のリンク先に記載されている。

なお、ArduinoIDEは1.8.9。ボードマネージャからインストールするESP32ライブラリはEspressif Systemsの2.0.10である(古いとコンパイルエラーになる)。

下記のスケッチ中の、「AudioPlayer player(source, i2s, decoder)」の組み合わせを変えることで、色々なプレーヤーを実装できる。


#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"

const char *urls[] = {
  "http://stream.srg-ssr.ch/m/rsj/mp3_128"
};
const char *wifi = "your_ssid";
const char *password = "your_password";

URLStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);

void setup() {
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Info);

  // setup output
  auto cfg = i2s.defaultConfig(TX_MODE);
  i2s.begin(cfg);

  // setup player
  player.begin();
}

void loop() {
  player.copy();
}

 

A2DPで接続したBluetoothスピーカーから音を出すプレイヤー

以下にスケッチと実験セットを示す。SDカードモジュール(写真ではタテになっている基板。Amazonから200円程度で入手できる)の接続方法は、上記の実装例に記載されている。mp3の楽曲をSDカードにコピーしてセットしておく。複数の曲をコピーした場合は一通り演奏後に停止する(その後は一旦電源を落とさないと「ファイル無」のエラーになる)。スケッチ中の「cfg.name」に、Bluetoothスピーカーのデバイス名を設定する。

なお、SDカードモジュールが手元に無い場合は、ESP32のSPIFFS領域にMP3のファイルを予めコピーしておく方法(プラグインの設定が必要。なお、このプラグインはArduinoIDEのVer2.x.xでは使用できないので注意)で実験できる(実装例はこちら、コピーするデータあり)。


#include "AudioTools.h"
#include "AudioLibs/AudioA2DP.h"
#include "AudioLibs/AudioSourceSDFAT.h"
#include "AudioCodecs/CodecMP3Helix.h"

const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSDFAT source(startFilePath, ext); // , PIN_AUDIO_KIT_SD_CARD_CS);
A2DPStream out;
MP3DecoderHelix decoder;
AudioPlayer player(source, out, decoder);

void setup() {
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);
  // setup output - We send the test signal via A2DP - so we conect to a Bluetooth Speaker
  auto cfg = out.defaultConfig(TX_MODE);
  cfg.name = "bbbbbbbbbb";  // set the device here. Otherwise the next available device is used for output
  cfg.auto_reconnect = true;  // if this is use we just quickly connect to the last device ignoring cfg.name
  out.begin(cfg);

  // setup player
  player.setVolume(0.7);
  player.begin();

}

void loop() {
  player.copy();
}

 

インターネットラジオを受信し、A2DPで接続したBluetoothスピーカーから音を出すプレイヤー(動作せず)

目的のプレイヤーである。実装例にはないが、上の2つを組み合わせれば(入力:インターネットラジオ、出力:Bluetoothスピーカー)実現できるはずである。実装例からの類推で作成したスケッチは以下の通り。

実行したところ、「E (17464) wifi_init_default: netstack cb reg failed with 257」というようなエラーとrebootを繰り返し、動作はしなかった。なお、以下のスケッチをコンパイルすると、プログラムサイズが1.7MBになるので、ArduinoIDEからPartition Schemeのサイズを「No OTA 2MB APP/ 2MB SPIFFS」に変更した。

 


#include "AudioTools.h"
#include "AudioLibs/AudioA2DP.h"
#include "AudioCodecs/CodecMP3Helix.h"
const char *urls[] = {
  "http://cast1.torontocast.com:2170/stream"
};
const char *wifi = "your_ssid";
const char *password = "your_password";

URLStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");

A2DPStream out;
MP3DecoderHelix decoder;
AudioPlayer player(source, out, decoder);

void setup() {
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);
  // setup output - We send the test signal via A2DP - so we conect to a Bluetooth Speaker
  auto cfg = out.defaultConfig(TX_MODE);
  cfg.name = "bbbbbbbbbb";  // set the device here. Otherwise the next available device is used for output
  cfg.auto_reconnect = true;  // if this is use we just quickly connect to the last device ignoring cfg.name
  out.begin(cfg);

  // setup player
  player.setVolume(0.9);
  player.begin();
}

void loop() {
  player.copy();
}