ESP32をBlueToothスピーカーにする

ESP32を使って簡単にBlueToothスピーカが出来ます。 Googleで検索すると多くのサイトがヒットしますが、ここが一番参考になりました。ー> https://github.com/pschatzmann/ESP32-A2DP 。

まずはハード

I2Sボード(SPEC:PCM5102)に有るパッドを前処理して、ESP32と下記の様に配線しました。

I2Sボードのコントロールは3本の信号線で行います。LCK:GIPO25 DIN:GPIO26 BCK:GPIO27。音の確認はボードのジャックにイヤフォンを挿入して行いました。

プログラム

サイトにI2Sのピンを指定するスケッチ(下記)が有ります。これを元に

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
    auto cfg = i2s.defaultConfig();
    cfg.pin_bck = 14;
    cfg.pin_ws = 15;
    cfg.pin_data = 22;
    i2s.begin(cfg);

    a2dp_sink.start("MyMusic");
}

void loop() {
}

これを元に、ピン指定部を今回の回路と合わせます。

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

void setup() {
    auto cfg = i2s.defaultConfig();
    cfg.pin_bck = 27;
    cfg.pin_ws = 25;
    cfg.pin_data = 26;
    i2s.begin(cfg);

    a2dp_sink.start("MyMusic");
}

void loop() {
}

ESP32-A2DParduino-audio-tools をLibrariesに追加してコンパイルすると、プログラムメモリーが足らないとエラーになりました。そこでESP32のPartitionSchemeを”Huge APP”に変更すると問題無くコンパイル出来ました。

スマホからこのESP32に接続して見ました。スマホのBluetooth接続の画面で接続先”MyMusic”を検索。検索後接続へと進むと問題無く接続出来ました。スマホのメディアプレーヤーで音楽を再生するとPCM5102から音声が出力されました。確かに動きます。

“AudioTools.h”をちょっとのぞくと

いろんな関数をユーザーが使用できる様になっています。その中の1つの virtual void set_address_validator を使えば、接続する相手に制限をかけれます。下記はその一例。

blue0.ino

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

#define     ad_num    2

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

bool check(esp_bd_addr_t adr){
  String valid_addr[ad_num] = {"xx:xx:xx:xx:xx:xx","yy:yy:yy:yy:yy:yy"};
  String in_addr;
  int a;
  bool fl;

    in_addr = a2dp_sink.to_str(adr);
    Serial.println(in_addr);
    fl = false;
    for(a = 0; a < ad_num; a ++){
      if(valid_addr[a] == in_addr){
        fl = true; 
        break;
      }
    }
  
    Serial.println(fl);
    return fl;
}

void setup() {
    Serial.begin(115200);
    delay(500);
    
    pinMode(RUN_LED, OUTPUT);
    digitalWrite(RUN_LED, 0);
    
    auto cfg = i2s.defaultConfig();
    cfg.pin_bck = 27;
    cfg.pin_ws = 25;
    cfg.pin_data = 26;
    i2s.begin(cfg);

    a2dp_sink.set_address_validator(check);
    a2dp_sink.start("MyMusic");
}

void loop() {
}
  • 21行: a2dp_sink.set_address_validator(check);
    • set_address_validatorの引数は実行したい関数となります。
    • 呼び出された関数内で制限の詳細を記述します。
    • 今回は、関数 ”check” と指定しています。
  • 9行: bool check(esp_bd_addr_t adr){
    • ここで制限内容を記述します。
    • 引数、esp_bd_addr_t adrは接続して来たユーザーのBlueToothのIDです。
    • この関数はbool宣言。戻り値が、true:接続許可。false:接続拒否となります。
    • 接続を許可するユーザーを配列 valid_addr[ad_num] に予め登録。(今回はIDを2つ登録)
    • 接続して来たユーザーIDと予め登録したIDを比較し有れば、trueを 無ければ、falseを返す。

プログラムを実行してスマホからアクセスすると、登録されていないスマホでもBlueToothの接続は出来るのですが音声をPCM5102から出す事は出来ませんでした。市販のBlueToothスピーカは誰でも接続出来、たまに全く関係ない人が接続してくる事が有ります。この関数を使う前は確かに簡単に接続出来るけど市販のBlueToothスピーカと同じ。なら市販のBlueToothスピーカの方が良いかと思っていましたが、この機能が使えるならこちらの方が良いと思いました。

このスケッチ、今回はBlueToothの受信機として使用していますが送信機の機能も持っています。プログラムに有る

  • virtual void play();      /// Starts to play music using AVRC
  • virtual void pause();     /// AVRC pause
  • virtual void stop();      /// AVRC stop
  • virtual void next();      /// AVRC next
  • virtual void previous();    /// AVRC previous
  • virtual void fast_forward();  /// AVRC fast_forward
  • virtual void rewind();     /// AVRC rewind

は受信機がメディアプレーヤーの場合それをコントロールする関数と思われます。今回はこれらのコマンドは使用していません。

起動、接続の確認

市販のBlueToothスピーカは起動時、接続時、音声で知らせてくれます。これも時として有り難いような迷惑なような機能です。このBlueToothスピーカにはそれらの機能が有りません。そこで、起動したら点滅。接続後点灯するLEDを追加しました。回路は下記の通り。前回の回路からGPIO33にLEDを接続したのみです。

プログラムは下記の通り、

blue1.ino

#include "AudioTools.h"
#include "BluetoothA2DPSink.h"

#define     RUN_LED   33
#define     ad_num    2

I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);

bool check(esp_bd_addr_t adr){
  String valid_addr[ad_num] = {"xx:xx:xx:xx:xx:xx","yy:yy:yy:y:y:yy"};
  String in_addr;
  int a;
  bool fl;

    in_addr = a2dp_sink.to_str(adr);
    Serial.println(in_addr);
    fl = false;
    for(a = 0; a < ad_num; a ++){
      if(valid_addr[a] == in_addr){
        fl = true; 
        break;
      }
    }
  
    Serial.println(fl);
    return fl;
}

void setup() {
    Serial.begin(115200);
    delay(500);
    
    pinMode(RUN_LED, OUTPUT);
    digitalWrite(RUN_LED, 0);
    
    auto cfg = i2s.defaultConfig();
    cfg.pin_bck = 26;
    cfg.pin_ws = 25;
    cfg.pin_data = 22;
    i2s.begin(cfg);

    a2dp_sink.set_address_validator(check);
    a2dp_sink.start("MyMu");
}

void loop() {
  int a = 1;

  while(1){
    if(a2dp_sink.is_connected()) a = 1;
    else a = ! a;
    digitalWrite(RUN_LED, a);
    
    Serial.println(a2dp_sink.get_connected_source_name());
    delay(500);
  }
}

BlueToothスピーカの起動、接続が分かり、接続出来るユーザを指定出来る様になりました。