Deciphering the Office 365 PSTN Usage Report

Background

Last week I received a bit of a mystifying alert from Office 365 letting me know that our pool of PSTN dial-out minutes for the month had been 80% consumed. This was mystifying due to the fact that as someone who has managed O365 for nearly a decade I didn’t realize there was a pool of minutes. PSTN (Public Switched Telephone Network) had to be related in some way or another to the capability my company has purchased from Office 365 to have a dial-in option added to our Microsoft Teams meetings. Any meeting we create has a dial-in number so that anyone who has a poor data connection can still dial a telephone and at least join the audio portion of the meeting.

While the main function of the Audioconferencing license is to provide that dial-in functionality, dial-out options also exist. For example, while in a Teams meeting if you realize you need someone else to participate you have the option to have Teams dial that person if you provide a phone number. Likewise, if you’re struggling in a low-coverage area you can tap a button in the Teams mobile app to have the service call you.

Sure enough (say what you want about Microsoft, but their documentation for Office 365 tends to be extremely good), I found the official confirmation. It just seems like a bit of a forgotten caveat considering you have to go to the legacy Skype portal to see it; the numbers are completely absent from the Teams portal:

You can monitor the usage against your dial-out minute pool in the “legacy” Skype for Business Admin Center. In the Microsoft Teams Admin Center, navigate to Legacy portal > Reports > PSTN Minute Pools. The Zone A dial-out minute pool will be labeled in the report as “Outbound Calls to Zone A Countries.”

Digging In

When I checked the total number of minutes we had in our pool, I did some quick math to confirm that we were allotted 60 dial-out minutes per Audioconferencing license that was assigned; purchased licenses that were not yet assigned to a user didn’t factor into the equation.

I was still a bit stumped as to who would be eating through our minutes, though, considering I figured dial-out to be a pretty niche feature. Luckily, the reporting section of the legacy Skype portal gives a report of how the minutes are used. There’s even an option to export it for a particular time range. I exported the data on the month-to-date in my tenant, which saved a .csv file. Opening it up showed me that there was still some work to do. The report listed dates for each call, the UPN (userPrincipalName) of the user, a source number, a destination number, and the duration of the call… in seconds. It also included both the dial-out information I wanted and the dial-in information that I don’t care about since that is unlimited. Ick.

I first fired up my text editor and put together a Python script. It weeded out any of the dial-in entries. For all of the dial-out entries, it added the UPN of the user to a list of dictionaries with a count of the seconds for their call. For each entry in the report, it was checked against my list of dictionaries, one for each user. If the user already had a dictionary in the list, the duration of that call was added to the user’s existing total. If the user wasn’t in the list yet, the script would append a new dictionary to the list for that user with the duration of the current call serving as their starting point. So the key for each dictionary was the UPN and the value was the number of seconds. Each dictionary in the list only needed one key-value pair.

I’m not sharing this initial version of the script because while the code worked perfectly, the logic was flawed. The report actually showed that Craft Brew Geek was using significantly more minutes than anyone else. While I was aware of the fact that he was frequently using his phone for Teams meetings while everyone is under quarantine due to his fixed-line provider having issues, I thought he was doing that via LTE rather than PSTN. He described his method of joining meetings to me, and he was literally tapping the “Join” button from the Teams app on his phone. To verify this was using LTE data, I even noted the LTE data consumed by the Teams app on my phone for the month, did a 10 minute Teams audio-only call with Brandi by joining the same way Craft Brew Geek was, and then checking the data usage again. Sure enough, it went up by 10 MB; this process wasn’t touching PSTN at all. I made doubly sure by assigning a policy to just my O365 account in Teams to block dial-out. I verified that tapping the “Join” button on my phone still worked fine while opting for the explicit “Dial me” option ended in an error.

The report also struck me as odd because it only listed 2 days for Craft Brew Geek, despite the fact that I know he’s been joining Teams calls the same way for 2 months now while we all work from home. I went back to the data this time paying attention to the source and destination numbers listed in the report. I noticed for all of Craft Brew Geek’s entries, the number listed as the source number was the number from Microsoft that we selected as the “default” number for our tenant due to it having the closest proximity to the majority of our employees. The destination number was the same every time as well, but it wasn’t Craft Brew Geek’s number. It was the number for a different employee in our company.

This is when I finally realized that the UPN listed in the report is not necessarily the UPN of the user who consumed the minutes; that wouldn’t even necessarily make sense considering you could have a meeting dial-out to an external participant (e.g. if you were using Teams to conduct an interview) or you may not have any telephone information stored for your users in Office 365. Instead, the UPN listed in the report is who scheduled the meeting.

Realizing that my logic was flawed due to the ambiguity of the report, I modified my script and replaced the UPN as the key in each dictionary with the destination telephone number. What I ended up with is this Python script. It’s quick and dirty since I wasn’t trying anything fancy; I just wanted a quick, sorted listing of our dial-out usage.

import csv


usage_tracker = {}

report_file = "./pstn_report.csv"
with open(report_file, "r", newline="") as csvfile:
    reader = csv.DictReader(csvfile)

    for row in reader:
        if row["Call Type"] == "conf_out":
            seconds = int(row["Duration Seconds"])
            if row["Destination Number"] in usage_tracker.keys():
                usage_tracker[row["Destination Number"]] += seconds
            else:
                usage_tracker[row["Destination Number"]] = seconds

usage_tuple_list = sorted(usage_tracker.items(), key=lambda x: x[1], reverse=True)

total_minutes = 0
for element in usage_tuple_list:
    current_minutes = round(element[1] / 60)
    total_minutes += current_minutes
    print(element[0] + ": " + str(current_minutes))

print("============================")
print(total_minutes)

At this point, all I needed to do was figure out who the telephone numbers my script spit out belonged to. Our company maintains a listing of numbers for each employee, so it was simple for me to search it for each entry. This showed us that one employee who was using dial-out heavily for himself as a matter of convenience during the quarantine was using basically all of our minutes.

Aftermath

The main takeaways from this incident are:

  1. Be mindful of the PSTN dial-out pool in Office 365 if you’re doing audioconferencing. I hadn’t thought of it because the O365 instance I managed previously was absolutely massive; this means we had significantly more minutes in the pool for a feature most people never use since the size of the pool is based on license assignment. Keep tabs on it in a smaller organization, especially when everyone is suddenly working remotely.
  2. The report from the legacy Skype admin center is pretty confusing, and it’s easy to mistake who is consuming dial-out minutes. Keep tabs on the destination number(s) in the report to find out who is actually doing it.

That’s it! Stay pink (from a socially acceptable distance, of course.)

The Dumpster Fire Of Remote Podcasting

As we mentioned in our last episode, we’ve switched to recording our podcast episodes remotely due to the fact that there’s currently a global pandemic happening. It’s been a big change considering that every other episode of both this podcast and the Same Shade of Difference podcast have been recorded in person.

Switching to a remote recording setup has been trying since, to be completely honest, most of the services for remote podcasting are horrible. They might be good services if you want to do some pretty hefty editing and audio engineering work; if you want just a means to do a recording and get a blended .wav or .mp3 file, though, things are surprisingly difficult.

SquadCast

The first service we tried was actually one that I tested with Craft Brew Geek for a recording of the Same Shade of Difference podcast. We gave SquadCast a try since we actually went to their booth at Podfest. The big claim to face for SquadCast is that it provides you with both audio and video. At the time of this writing it won’t record the video feed, but it honestly can’t be overstated how beneficial it is to see the people you’re recording with. Being able to see body language and facial expressions does a lot for helping the conversation proceed more smoothly and to prevent everyone from accidentally talking over one another.

Unfortunately, the execution of SquadCast left quite a bit to be desired. The first issue we had with SquadCast is that, when everything is said and done, it provides a .wav file for each participant. You have to piece the files together on your own, which is not the simple, streamlined experience we had been hoping for. It gets worse, though, because we discovered that any time someone switches their audio input (e.g. if you have a less technically inclined guest who keeps having connectivity problems with their Bluetooth microphone), it completely stops the recording for everyone. So we ended up having 3 .wav files for each of the 4 participants of our recording session. That’s 12 .wav files of all variable lengths that we would’ve needed to painstakingly put together.

If having that many files feels ridiculous, apparently whoever does the frontend development for SquadCast agrees; their Dashboard that gives access to the recordings wouldn’t even properly render all 12 files for Mark to download them. He actually had to use his browser’s function to zoom out so that the UI would properly render access to all of the files. Ick!

Zencastr

After such a terrible experience with SquadCast, Brandi and I decided we weren’t even going to bother with attempting to use it for the Unusually Pink Podcast. Instead, we decided to give Zencastr a shot. Zencastr is a fairly popular option, and it’s also currently making its service completely free while everyone is stuck at home due to COVID-19. Big kudos to them for that!

Unlike SquadCast, Zencastr is focused on the audio only; you don’t get a video feed. However, what you do get is the same, janky mess of individual .wav files for each participant. To not repeat the mistakes Mark and I made, Brandi and I just attempted a couple of quick, test-drive recordings with Zencastr so we didn’t record an entire episode that we ended up scrapping a la SquadCast. I’m 100% willing to own responsibility for doing something incorrectly, but Brandi and I also ended up with multiple files from Zencastr. Not only were there individual .wav files for each of us, but Brandi’s recording randomly had two .wav files, and the duration of her two files combined was still less than the duration of my single .wav file.

Once again, we may have been able to splice them together, but that’s not the workflow we want; we’ve been spoiled by having the RODECaster Pro spit out a single, combined .wav file that we can do any edits on.

Anchor

I’ve seen lots of chatter about Anchor being the most drop-dead simple option for podcast recording, so I figured I’d spend a little time digging into its options. Unfortunately, it seems to fall into the same mobile-first trap as Google WiFi where all other functionality is severely limited. For example, operating out of the web app for Anchor only gives you the option to record a solo episode; you can’t seem to loop in any other audio feeds.

The Anchor mobile app, however, does allow you to record with multiple people at the same time. We strongly wanted to avoid operating from mobile, though, because both Brandi and I have at least decent-ish USB microphones we wanted to use without trying to go through dongle-hell to connect them to a phone or tablet.

Anchor’s other oddity is that it seems to operate under the assumption that it will be your podcast hosting platform. We would essentially need to take the recording for our episode and have it published to Anchor; only instead of the Anchor RSS feed being dispersed to all of the big podcast platforms, we’d then need to download a local copy of the recording from Anchor in order to edit and re-upload to our actual host.

Ringr

The last service Brandi and I attempted was Ringr. To be honest, the service seemed more than a little sketch initially. The web app was listed as being a “beta” with the more established option being the mobile apps. Brandi and I quickly glanced at their mobile apps in our respective app stores only to discover that neither the iOS or Android apps had been updated in over a year. Regardless, we did a quick test with the Ringr desktop app and, amazingly, had decent luck (other than a minor, non-Ringr specific caveat that I’ll mention at the end.) The two of us were able to do a recording in Ringr and get a plethora of recording options after the fact. We could simply download an .mp3 file that had both of our audio feeds combined together. If we wanted a lossless option and had something to handle the format (GarageBand won’t), we could also download a FLAC file with the audio from each of us combined. Or, if we actually wanted what the other services offered, we could download raw .wav files with an individual file for each input.

Suffice to say, we were happy enough to snag the .mp3 that had both audio feeds spliced together and move on. Ringr seems to operate by recording at each end, and then once the recording is stopped the web app will upload the audio from each endpoint (you have to wait for it to do this prior to closing the browser window for your recording session) and then splice it together. Additionally, it seems to do some post-processing on the audio files. For example, during our initial recording tests Brandi noted that she could actually hear white noise from my end due to my microphone picking up the sound of my refridgerator kicking on. In the finished .mp3, though, the white noise was nowhere to be found.

Ringr is far from perfect, though, Like most options, it doesn’t provide any video. Brandi and I had to be careful to avoid speaking over one another… and we still struggled with it. While our first episode recorded with Ringr seemed fine, in the second episode Brandi was randomly disconnected from the call. While Ringr gives you options to reconnect to a disconnected call, it never actually works. The few times we ran into this scenario, Brandi and I would end up in separate instances of the same call, without any ability to hear one another. So we’d need to schedule a brand new call and start over again. In the instance where she got disconnected near the end of an episode, I just tried to do the outro on my own once I realized what was happening and we were able to salvage the situation. It’s extremely janky, though, and would’ve been much more problematic if it happened around the halfway point in our recording session instead of at the end.

While that’s a significant problem, Ringr has still been the best option for us by far. If you’re struggling to record your podcast remotely during quarantine, our recommendation would be to check out Ringr for the easiest experience.

macOS And Firefox Caveat

We did run into a caveat for any web-based services; as of the time of this writing there seems to be an issue when using a Blue Snowball USB microphone as your audio input with Firefox in macOS. When I initially tried using SquadCast with Mark, my microphone sounded like absolute trash; I sounded like a robot transmitting my audio over an extremely static-filled connection from an OG Soviet submarine. After switching from Firefox to Chrome, though, the issues went away. Brandi saw the same behavior when joining Ringr calls through Firefox. As soon as I asked her to switch to a different browser, though, everything was fine. While I personally try to avoid using Chrome whenever possible in favor of Firefox or Safari, in this instance the safest bet is to use Chrome for any recording just because it seems to be the best supported option.

Podfest Multimedia Expo

Over a month ago now at the beginning of March, Craft Brew Geek and I had the opportunity to attend the Podfest Multimedia Expo, the largest indie podcast conference in the world. While it was a bit of a scary experience to travel and attend when the coronavirus was just starting to make waves in the United States (which wasn’t aided by an over 4 hour delay at the airport for our flight back home), it was still a great conference even if it was plagued by a poor venue and questionable organization.

The sessions at Podfest covered a wide range of topics. Interested in video? Audio drama? Traditional podcasting? Marketing? The technical aspects of recording and audio engineering? There was something there for you to get some value. The organization of it all was pretty clunky, though. The first day of the conference was dedicated to a sub-conference called “Vidfest”, and that required a different pass than the “standard” pass. So while you could arrive for the first day to check in and get your badge, there was nothing for you to attend.

The second day focused on break-out sessions. These were also broken out into different categories, access to which once again was dependent upon the type of pass you had purchased. This resulted in a lot of people with the general attendance pass being limited to a small number of breakout sessions that were being conducted in rooms without nearly enough seating; many sessions I had to stand and people were spilling out of the doors into the hallways. After a break for lunch, we decided to pick a room that seemed to have the most promising sessions for the remainder of the day, get there early to snag seats in the back, and simply NEVER leave to avoid giving them up.

The third day felt like what should have been the first day; the entire morning was dedicated to the keynote… which we may have arrived a little early for if the photo above is an indication that we had literally the entire room to ourselves for about 30 minutes. The afternoon had more breakout sessions, though at this point everything was open to all attendees. While the rooms were still more crowded than I would’ve liked, it wasn’t quite as bad as the day prior. The last day followed this and just had a morning of breakout sessions.

Overall it was a fun experience, even with the looming specter of COVID-19 hanging over everything. I learned a few things I was able to use to help in my own podcasts, with good timing considering how we’ve switched to remote recording for both the Unusually Pink Podcast and the Same Shade of Difference Podcast while everyone is self-quarantining.

One of the big benefits of the event was that it was held in Orlando, which has plenty of things to do. I can only hope future events pick a venue with much more space (a complaint the organizers made known they were already well aware of by the time of the keynote.) Craft Brew Geek and I spent our first day patrolling the area for cool street art. While some of my favorites we came across are above, be sure to follow his Instagram account so see everything we saw on this trip and more.

Being the professionals that we are, Craft Brew Geek and I selected our hotel not for proximity to the conference (we had about a 30 minutes drive to get there each day), but for proximity to breweries in the area. It’s important to have priorities. We visited many cool places, including Dead Lizard, RockPit, Hourglass, Crooked Can, and Ten10. They were all terrific places, though RockPit was my favorite of the trip. They had amazing beer, terrific service, great WiFi, and excellent food from the barbeque joint next door. We spent about 6 hours sitting there drinking, eating, and working on the day we arrived in Orlando. We were able to put up stickers both there and at Dead Lizard. Ten10 is worthy of note for not only having excellent beer and food, but for being the first brewery I’ve ever seen to block VPN access on their WiFi. I even got to satisfy my taste for liquor by enjoying Delaney’s Tavern’s take on the Old Fashioned: a New Fashioned.

One of the coolest experiences of the trip happened at Dead Lizard, though, where we took over a table and set up all of our equipment to record a podcast on-location. It was a fun time, and it showed us that our travel podcast setup works pretty nicely… even if the microphone stands are entirely too heavy. The TSA apparently agreed since they had to open my bag and see what the hell I had in it.

On the whole, I definitely had an enjoyable trip. I learned plenty of new things at the event, got to see the sights in Orlando, had an opportunity to catch up with some family I rarely see, and (of course) drink a LOT of great beer. I’m also glad I was able to go on a trip immediately preceding the current lockdown as a means of holding off the cabin fever we’re all currently experiencing.